从返回 IContextMenu::QueryContextMenu 的菜单中删除“包含在库中”项

问题描述 投票:0回答:1

我需要从文件夹的

Include in library
返回的菜单中删除
IContextMenu::QueryContextMenu
项目。问题是
Include in library
菜单没有动词,我无法将它与任何内容进行比较以在
hMenu
列表中找到它并将其删除。

有没有办法从

Include in library
结果中排除
IContextMenu::QueryContextMenu

我发现的一个解决方案是删除

HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Folder\ShellEx\ContextMenuHandlers\Library Location
之前的
QueryContextMenu
键并在之后恢复它,但是访问
HKEY_LOCAL_MACHINE
需要管理员权限。

我的问题是,如何在没有管理员权限的情况下删除

Include in library
项目?

为了进行测试,您可以运行以下代码。您可以在“path”变量值中指定您的文件夹。


#include <windows.h>
#include <shlobj.h>

LPCWSTR path = L"c:\\users\\currentuser\\folder";

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    const int buttonId = 1;
    const int buttonX = 10;
    const int buttonY = 10;
    switch (message)
    {
    case WM_CREATE:
        CreateWindow(L"BUTTON", L"Show Context menu", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, buttonX, buttonY, 200, 30, hwnd, (HMENU)(long)buttonId, nullptr, nullptr);
        break;

    case WM_COMMAND:
        if (LOWORD(wParam) == buttonId)
        {
            IShellItem* item;

            SHCreateItemFromParsingName(path, NULL, IID_PPV_ARGS(&item));
            if (item)
            {
                IContextMenu* cm;
                item->BindToHandler(nullptr, BHID_SFUIObject, IID_PPV_ARGS(&cm));
                if (cm)
                {

                    auto menu = CreatePopupMenu();
                    const int firstId = 1;
                    cm->QueryContextMenu(menu, 0, firstId, 0x7FFF, CMF_NORMAL);
                    POINT pt{ buttonX, buttonY };
                    ClientToScreen(hwnd, &pt);
                    auto cmd = TrackPopupMenu(menu, TPM_RETURNCMD, pt.x, pt.y, 0, hwnd, nullptr);
                    if (cmd)
                    {
                        CMINVOKECOMMANDINFO cmi{};
                        cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
                        cmi.lpVerb = (LPSTR)MAKEINTRESOURCE(cmd - firstId);
                        cmi.nShow = SW_SHOWNORMAL;
                        cm->InvokeCommand(&cmi);
                    }

                    cm->Release();
                    DestroyMenu(menu);
                }
                item->Release();
            }
        }
        break;

    case WM_DESTROY:
        PostQuitMessage(0);
        break;

    default:
        return DefWindowProc(hwnd, message, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    auto hmod = LoadLibrary(L"shell32.dll");
    auto fileIconInit = (BOOL(WINAPI*)(BOOL))GetProcAddress(hmod, MAKEINTRESOURCEA(660));
    if (fileIconInit)
    {
        fileIconInit(TRUE);
    }

    WNDCLASS wc = {};
    wc.lpfnWndProc = WndProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = L"MyWindowClass";
    RegisterClass(&wc);

    auto hwnd = CreateWindow(wc.lpszClassName, L"Context Menu", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, hInstance, nullptr);
    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    MSG msg;
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return 0;
}
c++ windows winapi registry windows-shell
1个回答
0
投票

大多数 Windows Shell 注册表都会在转到

HKEY_CURRENT_USER
之前调用测试
HKEY_LOCAL_MACHINE

当他们访问

Software\Classes
子键时,通常通过 HKEY_CLASSES_ROOT 根键(这是一个 合并视图)或 HKCU 和 HKLM 来完成。

所以在这种情况下,我们可以使用

HKEY_CURRENT_USER\Software\Classes\Folder\ShellEx\ContextMenuHandlers\Library Location
键并将 对 Shell 无效的内容放入默认值中。该值不应该是 CLSID,或者如果是,它应该是一个与任何真实 COM 对象的 CLSID 不匹配的 CLSID,例如随机 guid。

© www.soinside.com 2019 - 2024. All rights reserved.