2014-11-14 2 views
0

Можно отобразить контекстное меню Windows для нескольких файлов, используя DisplayContextMenu form JEDI JCL library?Можно отобразить контекстное меню Windows для нескольких файлов, используя формулу библиотеки DisplayContextMenu JEDI JCL?

Это код:

function DisplayContextMenu(const Handle: THandle; const FileName: string; 
    Pos: TPoint): Boolean; 
var 
    ItemIdList: PItemIdList; 
    Folder: IShellFolder; 
begin 
    Result := False; 
    ItemIdList := PathToPidlBind(FileName, Folder); 
    if ItemIdList <> nil then 
    begin 
    Result := DisplayContextMenuPidl(Handle, Folder, ItemIdList, Pos); 
    PidlFree(ItemIdList); 
    end; 
end; 

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; 
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; 
+1

Да, это возможно. Метод GetUIObjectOf принимает массив 'PItemIDList' (его перевод искалечен хотя бы в Delphi XE3). Поэтому вам нужно построить массив 'PItemIDList' и передать его методу GetUIObjectOf. – TLama

ответ

2

Чтобы показать контекстное меню из нескольких пунктов, вы должны изменить код немного.

Сначала вы должны выделить массив PItemIDList и заполнить каждый элемент массива и, наконец, передать методу GetUIObjectOf массив с количеством элементов.

Попробуйте этот образец

uses 
    JclShell, 
    ShlObj; 

function MenuCallback(Wnd: THandle; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; 
var 
    ContextMenu2: IContextMenu2; 
begin 
    case Msg of 
    WM_CREATE: 
     begin 
     ContextMenu2 := IContextMenu2(PCreateStruct(lParam).lpCreateParams); 
     SetWindowLongPtr(Wnd, GWLP_USERDATA, LONG_PTR(ContextMenu2)); 
     Result := DefWindowProc(Wnd, Msg, wParam, lParam); 
     end; 
    WM_INITMENUPOPUP: 
     begin 
     ContextMenu2 := IContextMenu2(GetWindowLongPtr(Wnd, GWLP_USERDATA)); 
     ContextMenu2.HandleMenuMsg(Msg, wParam, lParam); 
     Result := 0; 
     end; 
    WM_DRAWITEM, WM_MEASUREITEM: 
     begin 
     ContextMenu2 := IContextMenu2(GetWindowLongPtr(Wnd, GWLP_USERDATA)); 
     ContextMenu2.HandleMenuMsg(Msg, wParam, lParam); 
     Result := 1; 
     end; 
    else 
    Result := DefWindowProc(Wnd, Msg, wParam, lParam); 
    end; 
end; 

function CreateMenuCallbackWnd(const ContextMenu: IContextMenu2): THandle; 
const 
    IcmCallbackWnd = 'ICMCALLBACKWND'; 
var 
    WndClass: TWndClass; 
begin 
    ZeroMemory(@WndClass, SizeOf(WndClass)); 
    WndClass.lpszClassName := PChar(IcmCallbackWnd); 
    WndClass.lpfnWndProc := @MenuCallback; 
    WndClass.hInstance := HInstance; 
    Winapi.Windows.RegisterClass(WndClass); 
    Result := CreateWindow(IcmCallbackWnd, IcmCallbackWnd, WS_POPUPWINDOW, 0, 
    0, 0, 0, 0, 0, HInstance, Pointer(ContextMenu)); 
end; 

type 
    PArrayOfPItemIDList = ^TArrayOfPItemIDList; 
    TArrayOfPItemIDList = array[0..0] of PItemIDList; 

function DisplayContextMenuPidl(const Handle: THandle; const Folder: IShellFolder; 
    Item: PArrayOfPItemIDList; ItemsCount :Integer; Pos: TPoint): Boolean; 
var 
    Cmd: Cardinal; 
    ContextMenu: IContextMenu; 
    ContextMenu2: IContextMenu2; 
    Menu: HMENU; 
    CommandInfo: TCMInvokeCommandInfo; 
    CallbackWindow: THandle; 
begin 
    Result := False; 
    if (Item = nil) or (Folder = nil) then 
    Exit; 
    //pass the number of elements oif the array (ItemsCount) 
    Folder.GetUIObjectOf(Handle, ItemsCount, Item[0], 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 
      ZeroMemory(@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; 

function DisplayContextMenu(const Handle: THandle; const FileNames: array of string; Pos: TPoint): Boolean; 
var 
    ItemIdList: PArrayOfPItemIDList; 
    Folder: IShellFolder; 
    ItemsCount : integer; 

    procedure AllocItems; 
    var 
    i : integer; 
    begin 
    for i := 0 to ItemsCount- 1 do 
     ItemIdList[i] := PathToPidlBind(FileNames[i], Folder); 
    end; 

    procedure ReleaseItems; 
    var 
    i : integer; 
    begin 
    for i := 0 to ItemsCount- 1 do 
     PidlFree(ItemIdList[i]); 
    end; 

begin 
    Result := False; 
    ItemsCount := Length(FileNames); 
    if ItemsCount>0 then 
    begin 
    //Allocate the array 
    ItemIdList := AllocMem(SizeOf(PItemIDList) * ItemsCount); 
    try 
     AllocItems; //fill each item 
     try 
     Result := DisplayContextMenuPidl(Handle, Folder, ItemIdList, ItemsCount, Pos); 
     finally 
     ReleaseItems; //release the items 
     end; 
    finally 
     FreeMem(ItemIdList); //release the array 
    end; 
    end; 
end; 

И использовать как так

DisplayContextMenu(Handle, ['C:\Foo\Bar.txt', 'C:\Foo\Bar2.txt'], Point(0, 0)); 
+0

E2010 Несовместимые типы: 'PItemIDList' и 'PArrayOfPItemIDList' <- при вызове 'DisplayContextMenuPidl' –

+0

Попробуйте этот образец http://pastebin.com/8nmiZbK3 (проверьте порядок единиц JclShell и ShlObj) – RRUZ

+0

Теперь' GetUIObjectOf 'возвращает NIL :( –

Смежные вопросы