Ein Rechtsklick im Hintergrundmenü zeigt defekte Elemente an
Posted: 05 Jan 2025, 17:06
Ich versuche, ein Rechtsklick-Hintergrundkontextmenü für einen Ordner anzuzeigen.
Das Menü wird angezeigt, aber es gibt die folgenden Probleme:
Sie können meinen Code unten sehen. Um diesen Code auszuführen und das Menü anzuzeigen, müssen Sie Folgendes tun:
Das Menü wird angezeigt, aber es gibt die folgenden Probleme:
- Wenn ich den Pfad zum Ordner als C:\Benutzer\Benutzername\Desktop\Folder\Child spezifiziere, erhalte ich ein Menü nicht für diesen Ordner, sondern für seinen übergeordneten Ordner, z C:\Benutzer\Benutzername\Desktop\Ordner (dies kann sein wird angezeigt, wenn Sie das Element „Eigenschaften“ ausführen, siehe: „Speicherort“ in Eigenschaften)
- Trotz Aufruf von HandleMenuMsg und HandleMenuMsg2 sind die Untermenüs für „ Zugriff gewähren auf“ werden nicht angezeigt
- Außerdem funktionieren Menüelemente, die von Drittanbieterprogrammen installiert wurden, nicht (z. B. „Git Gui Here“) ", "Git Bash Here", ...)
Sie können meinen Code unten sehen. Um diesen Code auszuführen und das Menü anzuzeigen, müssen Sie Folgendes tun:
- Ersetzen Sie den filePath-Wert durch den Pfad zum Ordner
- Drücken Sie die Schaltfläche „Kontextmenü“, um das Kontextmenü anzuzeigen
Code: Select all
#include
#include
#include
#include
#include
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 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;
}