我使用的是vc6.0。右键单击列表框项目时加载弹出菜单。但当我单击弹出菜单项时,似乎没有发送 WM_COMMAND 消息。在谷歌搜索后我对此没有任何线索。有谁知道吗
void PT_OnContextMenu(HWND hwnd, HWND hwndContext, UINT xPos, UINT yPos)
{
HWND hList = GetDlgItem(hwnd,IDC_LIST_PRESTYPE);
if (hList == hwndContext)
{
if(-1!=indexLB)
{
RECT rect;
POINT pt;
pt.x = xPos;
pt.y = yPos;
ListBox_GetItemRect(hwndContext, indexLB, &rect);
ScreenToClient(hwndContext, &pt);
if(PtInRect(&rect, pt))
{
HMENU hMenu = LoadMenu((HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), MAKEINTRESOURCE(IDR_MENU_RDELTYPE));
if(hMenu)
{
HMENU hpop = GetSubMenu(hMenu,0);
ClientToScreen(hwndContext, &pt);
TrackPopupMenu(hpop,
TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON,
pt.x,
pt.y,
0,
hwndContext,
NULL);
DestroyMenu(hMenu);
}
}
}
}
}
在下面的代码中未收到消息框。
void PT_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
switch(id)
{
case ID_MENUITEM_RDELTYPE:
{
MessageBox(hwnd,TEXT("dddd!"),TEXT("dddd"),MB_OK);
}
break;
default:
break;
}
}
解决了。在MSDN
上找到了它A handle to the window that owns the shortcut menu. This window receives all messages
from the menu. The window does not receive a WM_COMMAND message from the menu until the
function returns. If you specify TPM_NONOTIFY in the uFlags parameter, the function does
not send messages to the window identified by hWnd. However, you must still pass a window
handle in hWnd. It can be any window handle from your application.
我将
hwnd
设置为列表框而不是对话框。
如果有人读到这个问题,您可以创建一个仅消息窗口来接收与菜单相关的消息。这是创建仅消息窗口的代码。
hWnd = CreateWindowExW(0, <CllassName>, null,
0, 0, 0, 0, 0, HWND_MESSAGE,
null, <hInstance>, null);
然后您可以使用
hWnd
功能中的TrackPopupMenu
。
但请记住一件事。如果您在调用 TrackPopupMenu 函数之前创建了此仅消息窗口,则您可能希望在 TrackPopupMenu 函数返回后或在 WM_EXITMENUPOPUP
消息中立即销毁它。在这两种情况下,您都不会在 wndproc 中收到 WM_COMMAND
消息。因为 WM_COMMAND
是在 TrackPopupMenu 函数返回后发送的。因此,如果用户单击任何菜单项,WM_COMMAND
就是 wndproc 中的最后一条消息。但如果没有,WM_EXITMENUPOPUP
将是最后一条消息。您如何知道何时销毁仅显示消息的窗口?
嗯,有一个技巧可以摧毁窗户。当 TrackPopupMenu
函数返回时,使用 PostMessageW
函数将用户消息(WM_USER + ?)发布到仅消息窗口。由于它的异步性质,它将把消息发布到调用线程的消息队列中并返回。但在 Windows 中,所有用户定义的消息(又名 WM_USER + ?
消息)只会在系统消息之后处理。因此您可以保证您的用户定义的消息将被处理WM_EXITMENUPOPUP
& WM_COMMAND
。如果你的编程语言支持这样的东西,那就很简单了。
enum uint CM_CMENU_DESTROY = WM_USER + 15;
void show_context_menu(LPCWSTR ClassName, HINSTANCE hInstance, HMENU pMenu)
{
HWND hWnd = CreateWindowExW(0, ClassName, null,
0, 0, 0, 0, 0, HWND_MESSAGE,
null, hInstance, null);
// Some languages supports 'defer'. This is Dlang. We can use scope.
scope(exit) PostMessageW(hWnd, CM_CMENU_DESTROY, 0, 0);
POINT pt;
// Check if pt.x & pt.y == -1, then you need to find the coordinates
GetCursorPos(&pt);
TrackPopupMenu(pMenu, 2, pt.x, pt.y, 0, hWnd, null);
}
现在您可以在
CM_CMENU_DESTROY
中销毁仅显示消息的窗口