右键背景菜单异常求助:路径错误、子菜单不显示等问题
文件夹右键背景上下文菜单问题
尝试为文件夹显示右键背景上下文菜单,菜单可正常弹出,但存在以下问题:
- 当指定文件夹路径为
C:\Users\Username\Desktop\Folder\Child时,显示的却是其父文件夹C:\Users\Username\Desktop\Folder的菜单(可通过执行“属性”项查看“位置”确认); - 尽管已调用
HandleMenuMsg和HandleMenuMsg2,“授予访问权限”的子菜单仍无法显示; - 第三方程序安装的菜单项(如“Git Gui Here”“Git Bash Here”等)无法正常工作。
我使用IShellFolder2::CreateViewObject来获取文件夹的右键背景菜单,以下是我的代码。运行代码并显示菜单需执行以下步骤:
- 将
filePath值替换为目标文件夹路径; - 点击“Context menu”按钮显示上下文菜单。
#include <windows.h> #include <shlobj.h> #include <string> #include <sstream> #include <iomanip> HINSTANCE hInst; LPCSTR szTitle = "WinAPI"; LPCSTR szWindowClass = "MYWINDOWCLASS"; const wchar_t* filePath = L"C:\\Users\\Username\\Desktop\\Folder\\Child"; class ContextMenu { public: IContextMenu2* getIContextMenu2() { return m_contextMenu2; } IContextMenu3* getIContextMenu3() { return m_contextMenu3; } void showContextMenu(const std::wstring& path, HWND hwnd, UINT xPos, UINT yPos) { IContextMenu* pcm = nullptr; IContextMenu* outPcm = nullptr; if (SUCCEEDED(GetUIObjectOfFolder(hwnd, path.c_str(), IID_IContextMenu, (void**)&pcm))) { if (GetContextMenu(pcm, (void**)&outPcm)) { HMENU hmenu = CreatePopupMenu(); if (hmenu) { if (SUCCEEDED(outPcm->QueryContextMenu(hmenu, 0, SCRATCH_QCM_FIRST, SCRATCH_QCM_LAST, CMF_CANRENAME))) { int idCmd = TrackPopupMenuEx(hmenu, TPM_RETURNCMD, xPos, yPos, (HWND)hwnd, NULL); InvokeCommand(outPcm, idCmd); if (m_contextMenu2) { m_contextMenu2 = nullptr; } if (m_contextMenu3) { m_contextMenu3 = nullptr; } outPcm->Release(); } } } } } private: const int SCRATCH_QCM_FIRST = 1; const int SCRATCH_QCM_LAST = 0x7FFF; IContextMenu2* m_contextMenu2 = nullptr; IContextMenu3* m_contextMenu3 = nullptr; HRESULT GetUIObjectOfFolder(HWND hwnd, LPCWSTR pszPath, REFIID riid, void** ppv) { *ppv = NULL; HRESULT hr; LPITEMIDLIST pidl; SFGAOF sfgao; if (SUCCEEDED(hr = SHParseDisplayName(pszPath, NULL, &pidl, 0, &sfgao))) { IShellFolder2* psf; LPCITEMIDLIST pidlChild; if (SUCCEEDED(hr = SHBindToParent(pidl, IID_IShellFolder2, (void**)&psf, &pidlChild))) { hr = psf->CreateViewObject(hwnd, riid, ppv); psf->Release(); } CoTaskMemFree(pidl); } return hr; } void InvokeCommand(IContextMenu* pContextMenu, UINT idCommand) { CMINVOKECOMMANDINFO cmi = { 0 }; cmi.cbSize = sizeof(CMINVOKECOMMANDINFO); cmi.lpVerb = (LPSTR)MAKEINTRESOURCE(idCommand - 1); cmi.nShow = SW_SHOWNORMAL; if (!SUCCEEDED(pContextMenu->InvokeCommand(&cmi))) { std::stringstream ss; ss << "Last error: " << GetLastError(); std::string report = ss.str(); MessageBoxA(NULL, report.c_str(), report.c_str(), 0); } } BOOL GetContextMenu(LPCONTEXTMENU icm1, void** ppContextMenu) { *ppContextMenu = NULL; if (icm1) { // since we got an IContextMenu interface we can // now obtain the higher version interfaces via that if (SUCCEEDED(icm1->QueryInterface(IID_IContextMenu3, ppContextMenu))) { m_contextMenu3 = (LPCONTEXTMENU3)*ppContextMenu; } else if (SUCCEEDED(icm1->QueryInterface(IID_IContextMenu2, ppContextMenu))) { m_contextMenu2 = (LPCONTEXTMENU2)*ppContextMenu; } if (*ppContextMenu) icm1->Release(); // we can now release version 1 interface, // cause we got a higher one else { *ppContextMenu = icm1; // since no higher versions were found } // redirect ppContextMenu to version 1 interface } else return (FALSE); // something went wrong return (TRUE); // success } }; ContextMenu contextMenu; LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); HMODULE hmod = LoadLibraryW(L"shell32.dll"); BOOL(WINAPI * FileIconInit)(_In_ BOOL fRestoreCache); FileIconInit = (BOOL(WINAPI*)(BOOL)) GetProcAddress(hmod, MAKEINTRESOURCEA(660)); if (FileIconInit) { FileIconInit(TRUE); } hInst = hInstance; WNDCLASSA wc = {}; wc.lpfnWndProc = WndProc; wc.hInstance = hInstance; wc.lpszClassName = szWindowClass; RegisterClassA(&wc); HWND hWnd = CreateWindowExA( 0, szWindowClass, szTitle, 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 msg.wParam; } LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { IContextMenu2* cm2 = contextMenu.getIContextMenu2(); IContextMenu3* cm3 = contextMenu.getIContextMenu3(); if (cm3) { LRESULT res; if (SUCCEEDED(cm3->HandleMenuMsg2(message, wParam, lParam, &res))) { return res; } } else if (cm2) { if (SUCCEEDED(cm2->HandleMenuMsg(message, wParam, lParam))) { return 0; } } switch (message) { case WM_CREATE: { CreateWindowA( "BUTTON", "Context menu", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 100, 100, 100, 30, hWnd, (HMENU)1, hInst, nullptr); break; } case WM_COMMAND: { if (LOWORD(wParam) == 1) { SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); contextMenu.showContextMenu(filePath, hWnd, 100, 100); } break; } case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; }
内容的提问来源于stack exchange,提问作者Joe J
相关产品推荐
相关产品推荐

