我需要从文件夹的
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;
}
大多数 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。