Anonymous
IContextMenu::QueryContextMenu возвращает неправильное меню
Сообщение
Anonymous » 03 янв 2025, 16:26
Я создаю контекстное меню, вызывая IContextMenu::QueryContextMenu.
Все в порядке, за исключением двух вещей, и обе эти проблемы возникают при отображении контекстного меню для папки администратора, что в моем случае это текущий пользователь.
Предполагая, что имя пользователя администратора — «Администратор», проблема возникает при попытке отобразить контекстное меню для папки C:\Users\Admin, а именно следующее проблемы:
Отсутствует меню «Свойства» (Почему? Если проверить контекстное меню через Проводник, то пункт «Свойства» предназначен для этой папки , но QueryContextMenu его не возвращает)
Не удалось запустить пункт меню «Восстановить предыдущие версии» (при попытке щелкнуть по этому элементу происходит ошибка. В окне сообщения отображается «Не указано». error", но это меню работает при выборе через "Проводник"), а GetLastError()
возвращает код ошибки 1223 ("Операция была отменена пользователем": но я ничего не отменяю)
Меню «Поделиться» не работает, когда filePath указывает на файл
Вы можете увидеть мой код ниже. Чтобы запустить этот код и отобразить меню, необходимо сделать следующее:
Замените значение filePath на путь к папке
Нажмите кнопку «Контекстное меню», чтобы отобразить контекстное меню.
Код: Выделить всё
#include
#include
#include
#include
#include
HINSTANCE hInst;
LPCSTR szTitle = "WinAPI";
LPCSTR szWindowClass = "MYWINDOWCLASS";
const wchar_t* filePath = L"C:\\Users\\Admin";
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(GetUIObjectOfFile(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();
}
}
}
}
}
void showFolderBackgroundContextMenu(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_NORMAL))) {
int idCmd = TrackPopupMenuEx(hmenu, TPM_RETURNCMD, xPos, yPos, (HWND)hwnd, NULL);
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 GetUIObjectOfFile(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))) {
IShellFolder* psf;
LPCITEMIDLIST pidlChild;
if (SUCCEEDED(hr = SHBindToParent(pidl, IID_IShellFolder, (void**)&psf, &pidlChild))) {
hr = psf->GetUIObjectOf(hwnd, 1, &pidlChild, riid, NULL, ppv);
psf->Release();
}
CoTaskMemFree(pidl);
}
return hr;
}
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 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) {
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);
//SHELLEXECUTEINFO shellInfo;
//ZeroMemory(&shellInfo, sizeof(SHELLEXECUTEINFO));
//shellInfo.cbSize = sizeof(SHELLEXECUTEINFO);
//shellInfo.fMask = SEE_MASK_INVOKEIDLIST;
//shellInfo.hwnd = hWnd;
//shellInfo.lpVerb = L"PreviousVersions";
//shellInfo.lpFile = filePath;
//ShellExecuteEx(&shellInfo);
//std::stringstream ss;
//ss 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;
}
Скриншот с неуказанной ошибкой:
Отсутствует скриншот пункта меню «Свойства».
Подробнее здесь:
https://stackoverflow.com/questions/793 ... rrect-menu
1735910783
Anonymous
Я создаю контекстное меню, вызывая IContextMenu::QueryContextMenu. Все в порядке, за исключением двух вещей, и обе эти проблемы возникают при отображении контекстного меню для папки администратора, что в моем случае это текущий пользователь. Предполагая, что имя пользователя администратора — «Администратор», проблема возникает при попытке отобразить контекстное меню для папки C:\Users\Admin, а именно следующее проблемы: [list] [*]Отсутствует меню «Свойства» (Почему? Если проверить контекстное меню через Проводник, то пункт «Свойства» предназначен для этой папки , но QueryContextMenu его не возвращает) [*]Не удалось запустить пункт меню «Восстановить предыдущие версии» (при попытке щелкнуть по этому элементу происходит ошибка. В окне сообщения отображается «Не указано». error", но это меню работает при выборе через "Проводник"), а GetLastError() возвращает код ошибки 1223 ("Операция была отменена пользователем": но я ничего не отменяю) [*]Меню «Поделиться» не работает, когда filePath указывает на файл [/list] Вы можете увидеть мой код ниже. Чтобы запустить этот код и отобразить меню, необходимо сделать следующее: [list] [*]Замените значение filePath на путь к папке [*]Нажмите кнопку «Контекстное меню», чтобы отобразить контекстное меню. [/list] [code]#include #include #include #include #include HINSTANCE hInst; LPCSTR szTitle = "WinAPI"; LPCSTR szWindowClass = "MYWINDOWCLASS"; const wchar_t* filePath = L"C:\\Users\\Admin"; 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(GetUIObjectOfFile(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(); } } } } } void showFolderBackgroundContextMenu(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_NORMAL))) { int idCmd = TrackPopupMenuEx(hmenu, TPM_RETURNCMD, xPos, yPos, (HWND)hwnd, NULL); 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 GetUIObjectOfFile(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))) { IShellFolder* psf; LPCITEMIDLIST pidlChild; if (SUCCEEDED(hr = SHBindToParent(pidl, IID_IShellFolder, (void**)&psf, &pidlChild))) { hr = psf->GetUIObjectOf(hwnd, 1, &pidlChild, riid, NULL, ppv); psf->Release(); } CoTaskMemFree(pidl); } return hr; } 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 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) { 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); //SHELLEXECUTEINFO shellInfo; //ZeroMemory(&shellInfo, sizeof(SHELLEXECUTEINFO)); //shellInfo.cbSize = sizeof(SHELLEXECUTEINFO); //shellInfo.fMask = SEE_MASK_INVOKEIDLIST; //shellInfo.hwnd = hWnd; //shellInfo.lpVerb = L"PreviousVersions"; //shellInfo.lpFile = filePath; //ShellExecuteEx(&shellInfo); //std::stringstream ss; //ss 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; } [/code] Скриншот с неуказанной ошибкой: [img]https://i.sstatic.net/wCNKDoY8 .png[/img] Отсутствует скриншот пункта меню «Свойства». [img]https://i.sstatic.net/65EyhKCB.png[/img] Подробнее здесь: [url]https://stackoverflow.com/questions/79323369/icontextmenuquerycontextmenu-returns-incorrect-menu[/url]