Loop through IContextMenu

前端 未结 2 1994
执念已碎
执念已碎 2021-01-14 10:37

How do I loop through all items and sub items of a IContextMenu and list all available verbs? So far, I have this working code extracted from JCL:

function D         


        
2条回答
  •  暗喜
    暗喜 (楼主)
    2021-01-14 11:27

    To enumerate the items of the context menu you can use the Windows Menu functions : GetMenuItemCount , GetMenuItemInfo, GetSubMenu.

    using these functions i wrote this function

    uses
    JclShell,
    ShlObj;
    
    function DisplayContextMenuInfo( const Folder: IShellFolder; Item: PItemIdList; List :TStrings): Boolean;
    
      function GetMenuItemCaption(const hSubMenu: HMENU; const MenuId: Integer): string;
      var
        MenuItemInfo: TMenuItemInfo;
      begin
        MenuItemInfo.cbSize := SizeOf(MenuItemInfo);
        MenuItemInfo.fMask := MIIM_STRING;
        SetLength(Result, 1024*Sizeof(Char));
        MenuItemInfo.dwTypeData := PChar(Result);
        MenuItemInfo.cch        := Length(Result)-1;
        if not GetMenuItemInfo(hSubMenu, MenuId, False, MenuItemInfo) then
          RaiseLastOSError;
        SetLength(Result, MenuItemInfo.cch*Sizeof(Char));
      end;
    
      Procedure LogGetMenuInfo(Menu: HMENU);
      var
        i             : Integer;
        ItemsCount    : Integer;
        MenuId        : Cardinal;
        Caption       : string;
      begin
         ItemsCount:=GetMenuItemCount(Menu);
    
         List.Add(Format('Number of items %d ',[ItemsCount]));
          for i:= 0 to ItemsCount - 1 do
          begin
            MenuId:=GetMenuItemID(Menu,i);
    
            case MenuId of
    
             Cardinal(-1) : begin
                              List.Add('');
                              List.Add(Format('Sub Menu',[]));
                              LogGetMenuInfo(GetSubMenu(Menu,i));
                            end;
             0            :
    
             else
                            begin
                              Caption:=GetMenuItemCaption(Menu, MenuId);
                              List.Add(Format('MenuId (Cmd) %d Caption %s  ',[MenuId,Caption]))
                            end;
    
            end;
          end;
    
      end;
    
    
    var
      ContextMenu: IContextMenu;
      Menu: HMENU;
    
    begin
      Result := False;
      if (Item = nil) or (Folder = nil) then  Exit;
      Folder.GetUIObjectOf(0, 1, Item, IID_IContextMenu, nil,  Pointer(ContextMenu));
      if ContextMenu <> nil then
      begin
        Menu := CreatePopupMenu;
        try
          if Menu <> 0 then
            if Succeeded(ContextMenu.QueryContextMenu(Menu, 0, 1, $7FFF, CMF_EXPLORE)) then
               LogGetMenuInfo(Menu);
        finally
          DestroyMenu(Menu);
        end;
      end;
    end;
    

    and call in this way

    var
      ItemIdList: PItemIdList;
      Folder    : IShellFolder;
      FileName  : string;
    begin
      FileName:= 'C:\Users\Dexter\Downloads\VirtualTreeview.pdf';
      ItemIdList := PathToPidlBind(FileName, Folder);
      if ItemIdList <> nil then
      begin
        DisplayContextMenuInfo( Folder, ItemIdList, Memo1.lines);
        PidlFree(ItemIdList);
      end;
    end;
    

    this will fill the TStrings passed as parameter with info like this :

    Number of items 26 
    MenuId (Cmd) 141 Caption Open with Adobe Reader X
    MenuId (Cmd) 142 Caption &Open
    MenuId (Cmd) 143 Caption &Print
    MenuId (Cmd) 146 Caption Run &Sandboxed
    MenuId (Cmd) 140 Caption Analizar con &AVG
    Sub Menu
    Number of items 28 
    MenuId (Cmd) 105 Caption Add To Send To
    MenuId (Cmd) 106 Caption Add To Templates
    MenuId (Cmd) 107 Caption Change Date && Time
    MenuId (Cmd) 108 Caption Change Extension: pdf
    MenuId (Cmd) 109 Caption Choose Program
    MenuId (Cmd) 110 Caption Command Prompt
    MenuId (Cmd) 111 Caption Copy/Move To Folder
    MenuId (Cmd) 112 Caption Copy Path
    MenuId (Cmd) 113 Caption Delete On Reboot
    MenuId (Cmd) 114 Caption Duplicate File
    MenuId (Cmd) 115 Caption Encrypt File
    MenuId (Cmd) 116 Caption Explore Rooted
    MenuId (Cmd) 117 Caption Extended Delete
    MenuId (Cmd) 118 Caption Extended Search && Replace     
    

    now using this function you can pass the menuid (cmd) which you want execute

    function InvokeContextMenuCommand(const Comnand: Cardinal; const Folder: IShellFolder; Item: PItemIdList): Boolean;
    var
      ContextMenu   : IContextMenu;
      CommandInfo   : TCMInvokeCommandInfo;
      Menu          : HMENU;
      CallbackWindow: THandle;
    begin
      Result := False;
      if Comnand=0 then exit;
    
      if (Item = nil) or (Folder = nil) then  Exit;
        Folder.GetUIObjectOf(0, 1, Item, IID_IContextMenu, nil,  Pointer(ContextMenu));
      if ContextMenu <> nil then
       begin
        Menu := CreatePopupMenu;
        try
          if Menu <> 0 then
          if Succeeded(ContextMenu.QueryContextMenu(Menu, 0, 1, $7FFF, CMF_EXPLORE)) then
          begin
            CallbackWindow:=0;
            TrackPopupMenu(Menu, TPM_LEFTALIGN or TPM_LEFTBUTTON or  TPM_RIGHTBUTTON or TPM_RETURNCMD, 0, 0, 0, CallbackWindow, nil);
            ZeroMemory(@CommandInfo, SizeOf(CommandInfo));
            CommandInfo.cbSize := SizeOf(TCMInvokeCommandInfo);
            CommandInfo.hwnd   := 0;
            CommandInfo.lpVerb := MakeIntResourceA(Comnand - 1);
            CommandInfo.nShow  := SW_SHOWNORMAL;
            Result := Succeeded(ContextMenu.InvokeCommand(CommandInfo));
          end;
        finally
         DestroyMenu(Menu);
        end;
       end;
    end;
    

    call in this way

    var
      ItemIdList: PItemIdList;
      Folder    : IShellFolder;
      FileName  : string;
    begin
      FileName:= 'C:\Users\Dexter\Downloads\VirtualTreeview.pdf';
      ItemIdList := PathToPidlBind(FileName, Folder);
      if ItemIdList <> nil then
      begin
        //calling the 141 Menuid = `Open with Adobe Reader X`
        InvokeContextMenuCommand(141,Folder, ItemIdList);
        PidlFree(ItemIdList);
      end;
    end;
    

提交回复
热议问题