C++ Windows 7-自定义窗口菜单项:未调用GetMsgProc挂钩

C++ Windows 7-自定义窗口菜单项:未调用GetMsgProc挂钩,c++,windows-7,menu,C++,Windows 7,Menu,我将直截了当地说:我通过Windows全局钩子添加到每个窗口的系统菜单中的自定义菜单项不会导致在用户单击GetMsgProc时调用它 以下是我如何添加菜单项: void HookCore::AppendTasksMenu(HWND windowHandle) { // make the popup menu and set up the appearance flags for the sub-items m_mnuMoveToTasks = CreatePopupMenu();

我将直截了当地说:我通过Windows全局钩子添加到每个窗口的系统菜单中的自定义菜单项不会导致在用户单击GetMsgProc时调用它

以下是我如何添加菜单项:

void HookCore::AppendTasksMenu(HWND windowHandle)
{
    // make the popup menu and set up the appearance flags for the sub-items
    m_mnuMoveToTasks = CreatePopupMenu();
    UINT tasksAppearanceFlags = MF_STRING | MF_ENABLED;

    //TODO: need to make proper iterator for MenuItemList
    list<MenuItemInfo*>::iterator iter;
    for (iter = m_menuItems->Begin(); iter != m_menuItems->End(); iter++)
    {
        // check if we are adding a separator
        if ((*iter)->GetSpecial() == MenuItemInfo::SEPARATOR)
        {
            AppendMenu(m_mnuMoveToTasks, MF_SEPARATOR, (*iter)->GetItemId(), NULL);
        }
        else
        {
            AppendMenu(m_mnuMoveToTasks,
                ((*iter)->IsChecked() ? tasksAppearanceFlags | MF_CHECKED : tasksAppearanceFlags),
                (*iter)->GetItemId(), (*iter)->GetItemName().c_str());
        }
    }

    // get the system menu and set up the appearance flag for our new system sub-menu
    HMENU mnuSystem = GetSystemMenu(windowHandle, FALSE);
    UINT itemAppearanceFlags =  MF_STRING | MF_ENABLED | MF_POPUP;

    AppendMenu(mnuSystem, MF_SEPARATOR, ID_MOVE_TO_TASK_SEP, NULL);
    // append the sub-menu we just created
    AppendMenu(mnuSystem, itemAppearanceFlags, (UINT_PTR)m_mnuMoveToTasks, MOVE_TO_TASK);
}
有什么想法吗?我的物品ID是否有误?获取单击项目ID的正确方法是什么

谢谢

更新:

基于下面的建议,我尝试在CallWndProc、CallWndProcRetProc、GetMsgProc和SysMsgProc中捕获“WM_SYSCOMMAND”和“WM_COMMAND”消息。未传递项目选择消息

我还尝试对菜单所属的窗口进行子类化,我的WndProc从未收到项目选择消息,尽管传递了其他消息,如“WM_MENUSELECT”和“WM_UNINITMENUPOPUP”

还有其他地方要检查的指示吗

更新2:

因此,当我对窗口进行子类化/取消子类化时,我会在CallWndProc钩子中进行。当我得到WM_INITMENUPOPUP消息时,我将子类化,当lParam等于NULL且HIWORDwParam等于0xFFFF时,当我得到用于菜单关闭的WM_MENUSELECT消息时,我将取消类化

我单击系统菜单,此时WM_INITPOPUPMENU将被提升,将鼠标光标移动到包含自定义项的子菜单中,然后单击其中一个项。在此过程中,我将收到的每条消息都记录在新的WndProc中。以下是我在测试期间在WndProc中收到的消息列表:

WM_INITMENUPOPUP
147 (0x0093) - what is this message?
148 (0x0094) [9 times] - what is this message?
WM_NCMOUSELEAVE
WM_ENTERIDLE [2 times]
WM_NOTIFY [2 times]
WM_ENTERIDLE [2 times]
WM_NOTIFY
WM_ENTERIDLE [11 times]
WM_MENUSELECT
WM_ENTERIDLE [5 times]
WM_MENUSELECT
WM_ENTERIDLE [6 times]
WM_MENUSELECT
WM_ENTERIDLE [7 times]
WM_MENUSELECT
WM_ENTERIDLE [8 times]
WM_NOTIFY
WM_ENTERIDLE [5 times]
WM_NOTIFY
WM_ENTERIDLE
WM_NOTIFY
WM_ENTERIDLE
WM_UNINITMENUPOPUP
WM_CAPTURECHANGED

当用户单击该项时,我希望看到的消息是WM_命令或WM_SYSCOMMAND。我对windows消息或使用windows API没有太多经验。这两条信息中的一条是正确的吗?这两个信息都不存在,但它应该存在,对吗?有什么我遗漏的吗?

好的,我找到了。我不知道为什么,但我没有在任何钩子中看到正确的消息。但是,如果我将窗口子类化,我会在WndProc中看到它。在上面的第二次更新中,我说我在子类化时看不到正确的消息-我取消分类太快了

这就是我的子类:

if (oldWndProc == -1)
{
    oldWndProc = SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)NewWndProc);
    currentSubclassedHandle = hwnd;
}
以下是我如何取消课程:

if (oldWndProc == -1)
{
    oldWndProc = SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)NewWndProc);
    currentSubclassedHandle = hwnd;
}
if (oldWndProc != -1)
{
    SetWindowLongPtr(currentSubclassedHandle, GWL_WNDPROC, (LONG)oldWndProc);
    oldWndProc = -1;
    currentSubclassedHandle = NULL;
}

我得到的消息是WM_SYSCOMMAND,其中wParam是自定义菜单项ID。在我在第二次更新中发布的最后一条消息之后不久,此消息将被传递到NewWndProc。

错误挂钩,WH_GETMESSAGE只看到来自消息队列的消息。发布消息。WM_SYSCOMMAND已发送,而不是发布。请尝试使用WH_CALLWNDPROC或WH_SYSMSGFILTER。谢谢您的快速回复。我确实在CallWndProc和CallWndProcRetProc中看到了这条消息。如何获取单击的项目的ID?MSDN在文档中没有提到它。正如我在我的原始帖子中所描述的,CWPSTRUCT的wParam只包含SC_MOUSEMENU值。我看错字段了吗?如果你的代码片段与此相关,我会很高兴的。您看到了错误的消息。SC_鼠标是打开系统菜单的鼠标。稍后单击。使用Spy++查看消息。单击菜单中的项目后,我在Spy++中收到了很多消息。我不确定哪些是相关的。WM_LBUTTONDOWN后的消息:一些未知消息0xC0E5发生2次;WM_LBUTTONUP;2个工作组;WM_CAPTURECHANGED;WM_菜单选择;WM_EXITMENULOOP;WM_NCHITTEST;我假设WM_EXITMENULOOP之后发生的事情是不相关的。