Estou tentando exibir um menu de contexto para uma determinada pasta e, para isso, implementei a classe ContextMenu, que você pode ver abaixo.
Durante a implementação, encontrei um problema ao exibir um dos ícones do submenu "Enviar para".
Depois de exibir o menu de contexto de uma pasta, expanda a lista de submenus para "Enviar para", o submenu chamado "Dispositivo Bluetooth" não tem um ícone.
Entretanto, quando exibo o menu de contexto pela segunda vez, esse ícone aparece.
Minha pergunta é: como posso fazer com que o ícone do submenu "Dispositivo Bluetooth" seja exibido imediatamente quando o menu de contexto for exibido pela primeira vez?
Para executar este código e exibir o menu, você precisa fazer o seguinte:
- Substitua o valor filePath pelo caminho para a pasta
- Pressione o botão "Menu de contexto" para exibir o menu de contexto
Novamente, quando eu pressiono "Menu de contexto" pela primeira vez, o ícone para "Enviar para" -> "Dispositivo Bluetooth" não aparece. Mas se você clicar em "Menu de contexto" uma segunda vez, o ícone aparecerá.
Além disso, como você pode ver na captura de tela, o menu "Propriedades" está faltando, não entendo o porquê.
#include <windows.h>
#include <shlobj.h>
#include <string>
HINSTANCE hInst;
LPCSTR szTitle = "WinAPI";
LPCSTR szWindowClass = "MYWINDOWCLASS";
const wchar_t* filePath = L"C:\\Users\\Username\\Folder";
class ContextMenu
{
public:
IContextMenu3* getIContextMenu()
{
return m_contextMenu;
}
void showContextMenu(const std::wstring& path, HWND hwnd, UINT xPos, UINT yPos)
{
IContextMenu* pcm = nullptr;
if (SUCCEEDED(GetUIObjectOfFile(hwnd, path.c_str(), IID_IContextMenu, (void**)&pcm))) {
if (SUCCEEDED(pcm->QueryInterface(IID_IContextMenu3, (void**)&m_contextMenu))) {
HMENU hmenu = CreatePopupMenu();
if (hmenu) {
if (SUCCEEDED(m_contextMenu->QueryContextMenu(hmenu, 0, SCRATCH_QCM_FIRST, SCRATCH_QCM_LAST, CMF_NORMAL))) {
TrackPopupMenuEx(hmenu, TPM_RETURNCMD, xPos, yPos, (HWND)hwnd, NULL);
DestroyMenu(hmenu);
m_contextMenu->Release();
m_contextMenu = nullptr;
}
}
pcm->Release();
}
}
}
void showFolderBackgroundContextMenu(const std::wstring& path, HWND hwnd, UINT xPos, UINT yPos)
{
IContextMenu* pcm = nullptr;
if (SUCCEEDED(GetUIObjectOfFolder(hwnd, path.c_str(), IID_IContextMenu, (void**)&pcm))) {
if (SUCCEEDED(pcm->QueryInterface(IID_IContextMenu3, (void**)&m_contextMenu))) {
HMENU hmenu = CreatePopupMenu();
if (hmenu) {
if (SUCCEEDED(m_contextMenu->QueryContextMenu(hmenu, 0, SCRATCH_QCM_FIRST, SCRATCH_QCM_LAST, CMF_NORMAL))) {
TrackPopupMenuEx(hmenu, TPM_RETURNCMD, xPos, yPos, (HWND)hwnd, NULL);
DestroyMenu(hmenu);
m_contextMenu->Release();
m_contextMenu = nullptr;
}
}
pcm->Release();
}
}
}
private:
const int SCRATCH_QCM_FIRST = 1;
const int SCRATCH_QCM_LAST = 0x7FFF;
IContextMenu3* m_contextMenu = 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))) {
IShellFolder2* psf;
LPCITEMIDLIST pidlChild;
if (SUCCEEDED(hr = SHBindToParent(pidl, IID_IShellFolder2, (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;
}
};
ContextMenu contextMenu;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
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) {
if (contextMenu.getIContextMenu()) {
LRESULT res;
contextMenu.getIContextMenu()->HandleMenuMsg2(message, wParam, lParam, &res);
}
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) {
contextMenu.showContextMenu(filePath,hWnd, 100, 100);
}
break;
}
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
antes de ligar
QueryContextMenu
você precisa ligarFileIconInit