POPUP菜单不发送WM_COMMAND消息

问题描述 投票:0回答:2

我使用的是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;
    }
}
winapi visual-c++ contextmenu visual-c++-6 popupmenu
2个回答
2
投票

解决了。在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
设置为列表框而不是对话框。


0
投票

如果有人读到这个问题,您可以创建一个仅消息窗口来接收与菜单相关的消息。这是创建仅消息窗口的代码。

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

中销毁仅显示消息的窗口
© www.soinside.com 2019 - 2024. All rights reserved.