Programowanie w języku Delphi » Gotowce

IContextMenu - jak dodać podmenu

Na bazie przykładu z delphi

plik ContSMenu.dpr

// This COM server defines a Context Menu shell extension.  This allows the user
// to right click on Delphi Project files (.DPR) from the Explorer and compile
// them using the DCC32.exe command line compiler.
 
library ContSMenu;
 
uses
  ComServ,
  ContextSM in 'ContextSM.pas';
 
exports
  DllGetClassObject,
  DllCanUnloadNow,
  DllRegisterServer,
  DllUnregisterServer;
 
begin
end.


//Context Submenu example based on Context Menu Example from Delphi Demos
//2008.10.02 - [email protected]
unit ContextSM;
 
interface
 
uses
  Windows, ActiveX, ComObj, ShlObj, Dialogs;
 
type
  TContextMenu = class(TComObject, IShellExtInit, IContextMenu)
  private
    FFileName: array[0..MAX_PATH] of Char;
  protected
    { IShellExtInit }
    function IShellExtInit.Initialize = SEIInitialize; // Avoid compiler warning
    function SEIInitialize(pidlFolder: PItemIDList; lpdobj: IDataObject;
      hKeyProgID: HKEY): HResult; stdcall;
    { IContextMenu }
    function QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst, idCmdLast,
      uFlags: UINT): HResult; stdcall;
    function InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult; stdcall;
    function GetCommandString(idCmd, uType: UINT; pwReserved: PUINT;
      pszName: LPSTR; cchMax: UINT): HResult; stdcall;
  end;
 
const
  Class_ContextMenu: TGUID = '{34F3EB16-59CE-4B1A-855C-BAE2ECD3FA09}';
 
implementation
 
uses ComServ, SysUtils, ShellApi, Registry;
 
//to potrzebne aby uzyskac nazwe pliku dla ktorego wywolano ( w uproszczeniu)
function TContextMenu.SEIInitialize(pidlFolder: PItemIDList; lpdobj: IDataObject;
  hKeyProgID: HKEY): HResult;
var
  StgMedium: TStgMedium;
  FormatEtc: TFormatEtc;
begin
  // Fail the call if lpdobj is Nil.
  if (lpdobj = nil) then begin
    Result := E_INVALIDARG;
    Exit;
  end;
 
  with FormatEtc do begin
    cfFormat := CF_HDROP;
    ptd      := nil;
    dwAspect := DVASPECT_CONTENT;
    lindex   := -1;
    tymed    := TYMED_HGLOBAL;
  end;
 
  // Render the data referenced by the IDataObject pointer to an HGLOBAL
  // storage medium in CF_HDROP format.
  Result := lpdobj.GetData(FormatEtc, StgMedium);
  if Failed(Result) then
    Exit;
  // If only one file is selected, retrieve the file name and store it in
  // FFileName. Otherwise fail the call.
  if (DragQueryFile(StgMedium.hGlobal, $FFFFFFFF, nil, 0) = 1) then begin
    DragQueryFile(StgMedium.hGlobal, 0, FFileName, SizeOf(FFileName));
    Result := NOERROR;
  end
  else begin
    FFileName[0] := #0;
    Result := E_FAIL;
  end;
  ReleaseStgMedium(StgMedium);
end;
 
 
function TContextMenu.QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst,
          idCmdLast, uFlags: UINT): HResult;
var
 hSubmenu:HMENU;
 id:Integer;
 mii:MENUITEMINFOA;
begin
  Result := 0; // or use MakeResult(SEVERITY_SUCCESS, FACILITY_NULL, 0);
 
 
  if ((uFlags and $0000000F) = CMF_NORMAL) or  ((uFlags and CMF_EXPLORE) <> 0) then begin
    // Add one menu item to context menu with submenus
 
    //First create popupmenu
    hSubmenu := CreatePopupMenu();
    id := idCmdFirst;
 
 
    //dodajemy submenu
    InsertMenu(hSubmenu, 0, MF_BYPOSITION, id, 'Pierwsze');
    inc(id);
    InsertMenu(hSubmenu, 1, MF_BYPOSITION, id, 'Drugie');
    inc(id);
 
 
    //oraz menu glowne
    FillChar(mii,sizeof(mii),0);
 
    mii.cbSize := sizeof(mii);
    mii.fMask := MIIM_SUBMENU or MIIM_ID or MIIM_TYPE or MIIM_STATE;
    mii.wID := id;
    mii.hSubMenu := hSubmenu;
    mii.fType := MFT_STRING;
    mii.fState := MFS_ENABLED;
    mii.dwTypeData := 'Submenu';
    inc(id);
 
    if (not InsertMenuItem(Menu, indexMenu, LongBool(True),  mii)) then
    begin
    //Error ....
    end;
 
 
   // Return number of menu items added
    Result := MakeResult(SEVERITY_SUCCESS, 0, id-idCmdFirst);
  end;
end;
 
function TContextMenu.InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult;
begin
  Result := E_FAIL;
  // Make sure we are not being called by an application
  if (HiWord(Integer(lpici.lpVerb)) <> 0) then
  begin
    Exit;
  end;
 
  //ten argument musi byc w zakresie naszych menu ID, znajduje sie ono w LoWord(Integer(lpici.lpVerb))
  // Make sure we aren't being passed an invalid argument number
  if (LoWord(lpici.lpVerb) > 2{high menu id}) then begin
    Result := E_INVALIDARG;
    Exit;
  end;
 
  try
    MessageBox(0,PChar('Odpalono submenu nr: '+IntToStr(LoWord(Integer(lpici.lpVerb)))),'',0);
    Result := NOERROR;
  finally
  end;
end;
 
function TContextMenu.GetCommandString(idCmd, uType: UINT; pwReserved: PUINT;
  pszName: LPSTR; cchMax: UINT): HRESULT;
begin
 
//To mozna rozwinac na podmenu tez ....
 
  if (idCmd = 0) then begin
    if (uType = GCS_HELPTEXT) then
      // return help string for menu item
      StrCopy(pszName, 'Compile the selected Delphi project');
    Result := NOERROR;
  end
  else
    Result := E_INVALIDARG;
end;
 
type
  TContextMenuFactory = class(TComObjectFactory)
  public
    procedure UpdateRegistry(Register: Boolean); override;
  end;
 
procedure TContextMenuFactory.UpdateRegistry(Register: Boolean);
var
  ClassID: string;
begin
  if Register then begin
    inherited UpdateRegistry(Register);
 
    ClassID := GUIDToString(Class_ContextMenu);
    CreateRegKey('DelphiProject\shellex', '', '');
    CreateRegKey('DelphiProject\shellex\ContextMenuHandlers', '', '');
    CreateRegKey('DelphiProject\shellex\ContextMenuHandlers\ContMenu', '', ClassID);
 
    if (Win32Platform = VER_PLATFORM_WIN32_NT) then
      with TRegistry.Create do
        try
          RootKey := HKEY_LOCAL_MACHINE;
          OpenKey('SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions', True);
          OpenKey('Approved', True);
          WriteString(ClassID, 'Delphi Context Menu Shell Extension Example');
        finally
          Free;
        end;
  end
  else begin
    DeleteRegKey('DelphiProject\shellex\ContextMenuHandlers\ContMenu');
    DeleteRegKey('DelphiProject\shellex\ContextMenuHandlers');
    DeleteRegKey('DelphiProject\shellex');
 
    inherited UpdateRegistry(Register);
  end;
end;
 
initialization
  TContextMenuFactory.Create(ComServer, TContextMenu, Class_ContextMenu,
    '', 'Delphi Context SubMenu(s) Shell Extension Example', ciMultiInstance,
    tmApartment);
end.