Вопрос о доступе к контекстному меню оболочки в Windows 10 - PullRequest
0 голосов
/ 10 октября 2018

Я пытаюсь получить контекстное меню оболочки, меню не будет отображаться, так как мне нужен только HMENU, чтобы получить имя и значки пунктов меню (включая элементы в подменю).Есть много статей, рассказывающих об этом в Интернете, и после них я успешно справляюсь с большинством из них.

Предоставляя PIDL выбранного элемента и пустое HMENU, мой код может получить верхний уровеньконтекстное меню оболочки без проблем.

// Callee need to DestroyMenu(hTopMenu);
HRESULT FillContextMenuFromPIDL(LPCITEMIDLIST pidl, HMENU hTopMenu)
{
    HRESULT ret = MAKE_HRESULT(SEVERITY_ERROR, 0, 0);

    IContextMenu *pcm;
    HRESULT hr;

    IShellFolder *psf;
    LPCITEMIDLIST pidlChild;
    if (SUCCEEDED(hr = SHBindToParent(pidl, IID_IShellFolder, (void**)&psf, &pidlChild))) {
        hr = psf->GetUIObjectOf(NULL, 1, &pidlChild, IID_IContextMenu, NULL, (void**)&pcm);
        // 0 was hWnd
        psf->Release();

        if (SUCCEEDED(hr)) {
            hr = pcm->QueryContextMenu(hTopMenu, 0, 1, 0x7FFF, 0x00020490);

            if (SUCCEEDED(hr)) {
                IContextMenu3* hContextMenu3 = NULL;
                IContextMenu2* hContextMenu2 = NULL;

                if (SUCCEEDED(pcm->QueryInterface(IID_IContextMenu3, (void**)&hContextMenu3))) {
                    LRESULT lres;

                    hContextMenu3->HandleMenuMsg2(WM_INITMENUPOPUP, (WPARAM)hTopMenu, 0, &lres);

                    for (int pos = 0; pos < GetMenuItemCount(hTopMenu); pos++) {
                        HMENU subMenu = GetSubMenu(hTopMenu, pos);
                        if (subMenu != NULL) {
                            LPARAM lparam = (LPARAM)(MAKELONG(pos, FALSE));
                            hContextMenu3->HandleMenuMsg2(WM_INITMENUPOPUP, (WPARAM)subMenu, lparam, &lres);
                        }
                    }
                    //hContextMenu3->Release();
                }

                if (SUCCEEDED( pcm->QueryInterface(IID_IContextMenu2, (void**)&hContextMenu2) )) {
                    for (int pos = 0; pos < GetMenuItemCount(hTopMenu); pos++) {
                        HMENU subMenu = GetSubMenu(hTopMenu, pos);
                        if (subMenu != NULL) {
                            LPARAM lparam = (LPARAM)(MAKELONG(pos, FALSE));
                            hContextMenu2->HandleMenuMsg(WM_INITMENUPOPUP, (WPARAM)subMenu, lparam);
                        }
                    }
                    //hContextMenu2->Release();
                }

                ret =  MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0);
            }

            //pcm->Release();
        }
    }

    return ret;
}

Предыдущие программисты упоминали, что для того, чтобы заставить 'Open with' и 'Send to' работать, вы должны переслать сообщение WM_INITMENUPOPUP в IContextMenu2: HandleMenuMsg и IContextMenu3: HandleMenuMsg2 вWndProc.Поскольку я не могу отобразить меню, я отправляю WM_INITMENUPOPUP этим двум интерфейсам и позволяю им добавлять динамические пункты меню.Это работает для «Открыть с помощью» и «Разрешить», но не для «Отправить».GetMenuItemCount () возвращает 1 для «Отправить».

Позже я провел эксперимент, я подключил WndProc своего рабочего стола и позволил ему отбросить все WM_INITMENUPOPUP, чтобы исходные WndProc и HandleMenuMsg не могли их видеть.«Открыть с помощью» и «Дать разрешение» перестали работать, как ожидалось, но, что интересно, пункты подменю «Отправлено» не были затронуты!Кроме того, GetMenuItemCount (HWND «Отправлено») в первом WM_INITMENUPOPUP дает 1, но дает правильное число в WM_INITMENUPOPUP «Отправлено», даже HandleMenuMsg его не получил!

Похоже на это 'Пункты меню «Отправить» добавляются после отображения меню верхнего уровня и до того, как подменю становится видимым.Есть ли обходной путь?Заранее спасибо!

...