2013-08-10 1 views
0

Я пытаюсь отобразить контекстное меню оболочки для файла (так же, как при щелчке правой кнопкой мыши по этому файлу в Проводнике) программно. Мне удалось сделать это для одного файла/папки, мой код ниже. Теперь, как я могу вызвать контекстное меню для списка файлов, как если бы я выбрал пару в Проводнике и щелкнул их?Вызов меню оболочки Windows (аналогично щелчку правой кнопкой мыши в проводнике) для нескольких файлов программным способом

bool openShellContextMenuForObject(const std::wstring &path, int xPos, int yPos, void * parentWindow) 
{ 
    assert (parentWindow); 
    ITEMIDLIST * id = 0; 
    std::wstring windowsPath = path; 
    std::replace(windowsPath.begin(), windowsPath.end(), '/', '\\'); 
    HRESULT result = SHParseDisplayName(windowsPath.c_str(), 0, &id, 0, 0); 
    if (!SUCCEEDED(result) || !id) 
     return false; 
    CItemIdListReleaser idReleaser (id); 

    IShellFolder * ifolder = 0; 

    LPCITEMIDLIST idChild = 0; 
    result = SHBindToParent(id, IID_IShellFolder, (void**)&ifolder, &idChild); 
    if (!SUCCEEDED(result) || !ifolder) 
     return false; 
    CComInterfaceReleaser ifolderReleaser (ifolder); 

    IContextMenu * imenu = 0; 
    result = ifolder->GetUIObjectOf((HWND)parentWindow, 1, (const ITEMIDLIST **)&idChild, IID_IContextMenu, 0, (void**)&imenu); 
    if (!SUCCEEDED(result) || !ifolder) 
     return false; 
    CComInterfaceReleaser menuReleaser(imenu); 

    HMENU hMenu = CreatePopupMenu(); 
    if (!hMenu) 
     return false; 
    if (SUCCEEDED(imenu->QueryContextMenu(hMenu, 0, 1, 0x7FFF, CMF_NORMAL))) 
    { 
     int iCmd = TrackPopupMenuEx(hMenu, TPM_RETURNCMD, xPos, yPos, (HWND)parentWindow, NULL); 
     if (iCmd > 0) 
     { 
      CMINVOKECOMMANDINFOEX info = { 0 }; 
      info.cbSize = sizeof(info); 
      info.fMask = CMIC_MASK_UNICODE; 
      info.hwnd = (HWND)parentWindow; 
      info.lpVerb = MAKEINTRESOURCEA(iCmd - 1); 
      info.lpVerbW = MAKEINTRESOURCEW(iCmd - 1); 
      info.nShow = SW_SHOWNORMAL; 
      imenu->InvokeCommand((LPCMINVOKECOMMANDINFO)&info); 
     } 
    } 
    DestroyMenu(hMenu); 

    return true; 
} 

ответ

2
result = ifolder->GetUIObjectOf((HWND)parentWindow, 1, (const ITEMIDLIST **)&idChild, IID_IContextMenu, 0, (void**)&imenu); 

GetUIObjectOf функция принимает массив из PIDLs. 1 в этом вызове функции указывает, что ваш массив содержит только 1 элемент, но вы можете передать любое количество дочерних PIDL с использованием того же метода. Например:

LPITEMIDLIST pidlArray[3] = { pidl1, pidl2, pidl3 }; 
result = ifolder->GetUIObjectOf((HWND)parentWindow, _countof(pidlArray), pidlArray, IID_IContextMenu, 0, (void**)&imenu); 

(В реальном мире вы будете строить свой массив динамически). Обратите внимание, что все элементы должны быть дочерними для одной родительской папки.

+0

Спасибо, это работает. Хотя кажется, что у меня утечка памяти. Какие объекты следует выделять отдельно от классов интерфейса и 'ITEMIDLIST', возвращаемых' SHParseDisplayName'? –

+0

Почему вы думаете, что есть утечка? Я не вижу утечки в коде, который вы показали. –