3

IContextMenuのすべてのアイテムとサブアイテムをループして、使用可能なすべての動詞を一覧表示するにはどうすればよいですか?これまでのところ、JCLから抽出されたこの作業コードがあります。

function DisplayContextMenuPidl(const Handle: THandle; const Folder: IShellFolder; Item: PItemIdList; Pos: TPoint): Boolean;
var
  Cmd: Cardinal;
  ContextMenu: IContextMenu;
  ContextMenu2: IContextMenu2;
  Menu: HMENU;
  CommandInfo: TCMInvokeCommandInfo;
  CallbackWindow: THandle;
  vteste : string;
begin
  Result := False;
  if (Item = nil) or (Folder = nil) then
    Exit;
  Folder.GetUIObjectOf(Handle, 1, Item, IID_IContextMenu, nil,
    Pointer(ContextMenu));
  if ContextMenu <> nil then
  begin
    Menu := CreatePopupMenu;
    if Menu <> 0 then
    begin
      if Succeeded(ContextMenu.QueryContextMenu(Menu, 0, 1, $7FFF, CMF_EXPLORE)) then
      begin
        CallbackWindow := 0;
        if Succeeded(ContextMenu.QueryInterface(IContextMenu2, ContextMenu2)) then
        begin
          CallbackWindow := CreateMenuCallbackWnd(ContextMenu2);
        end;
        ClientToScreen(Handle, Pos);
        Cmd := Cardinal(TrackPopupMenu(Menu, TPM_LEFTALIGN or TPM_LEFTBUTTON or TPM_RIGHTBUTTON or TPM_RETURNCMD, Pos.X, Pos.Y, 0, CallbackWindow, nil));
        if Cmd <> 0 then
        begin
          ResetMemory(CommandInfo, SizeOf(CommandInfo));
          CommandInfo.cbSize := SizeOf(TCMInvokeCommandInfo);
          CommandInfo.hwnd := Handle;
          CommandInfo.lpVerb := MakeIntResourceA(Cmd - 1);
          CommandInfo.nShow := SW_SHOWNORMAL;
          Result := Succeeded(ContextMenu.InvokeCommand(CommandInfo));
        end;
        if CallbackWindow <> 0 then
          DestroyWindow(CallbackWindow);
      end;
      DestroyMenu(Menu);
    end;
  end;
end;

このコードは正常に機能し、コンテキストメニューを表示します。すべてのメニューとサブメニューの動詞を(おそらくログファイルで)リストできるように調整する必要があります。

編集

明確にするために、私がこのコンテキストメニューを持っていると仮定しましょう:

ここに画像の説明を入力してください

次のようなログを記録したい:

アイテム 動詞

open=オープン
プロパティ=プロパティ
sendto= sendto
send to bluetooh = xxx

編集

誰かが動詞を取得したり、表示テキストでアイテムを呼び出す別の方法がある場合は、それもありがたいです。

4

2 に答える 2

5

コンテキスト メニューの項目を列挙するには、Windows を使用できますMenu functions: GetMenuItemCountGetMenuItemInfoGetSubMenu

これらの関数を使用して、私はこの関数を書きました

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;

このように呼び出します

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;

これにより、パラメーターとして渡された TStrings に次のような情報が入力されます。

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     

この関数を使用して、実行したいメニューID(cmd)を渡すことができます

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;

このように呼びます

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;
于 2011-04-20T17:13:06.207 に答える
2

メニューを呼び出すと、ほとんどQueryContextMenuのメニューが表示されます。メニューのハンドルを知っているので、その項目を反復して必要な情報を取得できます。

function DisplayContextMenuPidl(const Handle: THandle; const Folder: IShellFolder; Item: PItemIdList; Pos: TPoint): Boolean;

//++
  procedure RecurseItems(const Menu: HMENU; Strings: TStrings; Indent: Integer = 0);

    function GetItemString(Parent: HMENU; Item: Integer): string;
    begin
      SetLength(Result, GetMenuString(Parent, Item, nil, 0, MF_BYPOSITION) + 1);
      GetMenuString(Parent, Item, PChar(Result), Length(Result), MF_BYPOSITION);
    end;

  var
    i: Integer;
    ItemInfo: TMenuItemInfo;
  begin
    for i := 0 to GetMenuItemCount(Menu) - 1 do begin
      FillChar(ItemInfo, SizeOf(ItemInfo), 0);
      ItemInfo.cbSize := SizeOf(ItemInfo);
      ItemInfo.fMask := MIIM_SUBMENU or MIIM_TYPE;
      GetMenuItemInfo(Menu, i, True, ItemInfo);
      if ItemInfo.fType <> MFT_SEPARATOR then
        Strings.Add(StringOfChar('-', Indent * 2) + GetItemString(Menu, i));
      if ItemInfo.hSubMenu <> 0 then
        RecurseItems(ItemInfo.hSubMenu, Strings, Indent + 1);
    end;
  end;
//--

var
  Cmd: Cardinal;
  ContextMenu: IContextMenu;
  ContextMenu2: IContextMenu2;
  ...

  begin
    Menu := CreatePopupMenu;
    if Menu <> 0 then
    begin
      if Succeeded(ContextMenu.QueryContextMenu(Menu, 0, 1, $7FFF, CMF_EXPLORE)) then

//++
      Memo1.Clear;
      RecurseItems(Menu, Memo1.Lines);
//--

      begin
        CallbackWindow := 0;
      ..


「IContextMenu2」インターフェイスを取得した後に項目のテキストを取得してもしなくても、実際には違いはありません。「送信先」や「新規」などのサブメニューは、親メニュー項目が選択されるまで入力されないためです。そのルーチンでは、それらにアクセスする方法はありません。上記のコードのサンプル出力で、展開に失敗した 2 つの項目の下に注意してください。

&開ける
管理者として実行
互換性のトラブルシューティング(&Y)
7-ジップ
--アーカイブを開く
--ファイルを解凍...
- ここで抽出
-- テスト アーカイブ
- アーカイブに加える...
と共有する
--
タスクバーに固定(&K)
スタートメニューにピン止めする
以前のバージョンを復元
に送る
--
切る
&コピー
ショートカットを作成する
&消去
プロパティ


サブアイテムを表示するメッセージは、WM_INITMENUPOPUP、WM_ENTERIDLE、WM_MEASUREITEM、WM_DRAWITEM など、CallbackWindow の WndProc を通過します。しかし、そこから情報を抽出しようとしても、まったく意味がないと思います..

于 2011-04-20T17:13:56.917 に答える