繁体   English   中英

我正在测试WM_MENUCHAR,但代码无法按预期工作

[英]I'm testing WM_MENUCHAR but the code doesn't work as expected

下面的示例使用仅带有System菜单的应用程序窗口,我正在尝试了解如何使用消息WM_MENUCHAR 该消息的MSDN文档说:

当菜单处于活动状态且用户按下与任何助记符或加速键不对应的键时发送。 此消息将发送到拥有该菜单的窗口。

在下面的示例中,每当我按下Alt + AAlt + B或其他任何键时, WM_MENUCHAR被发送到窗口proc。

我假设Alt键激活系统菜单,因为发送到WndProc()所有WM_MENUCHAR消息都有HIWORD(wParam) = MF_SYSMENU并且消息被发送到窗口的原因是由于程序没有没有加速器表,系统菜单也不包含任何助记符。

这一点对我来说是不明确的:响应WM_MENUCHAR ,代码返回MAKELPARAM(5, MNC_SELECT)但该返回值不会调用System菜单中的Close菜单项(请记住5是base-0顺序)系统菜单中此菜单项的编号。 我错过了什么?

#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pszCmdLine, int nCmdShow)
{
    WNDCLASSEX  wndclassx;

    wndclassx.cbSize = sizeof(WNDCLASSEX);
    wndclassx.style = CS_HREDRAW | CS_VREDRAW;
    wndclassx.lpfnWndProc = WndProc;
    wndclassx.cbClsExtra = 0;
    wndclassx.cbWndExtra = 0;
    wndclassx.hInstance = hInstance;
    wndclassx.hIcon = 0;
    wndclassx.hCursor = LoadCursor(0, IDC_ARROW);
    wndclassx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wndclassx.lpszClassName = L"WndProc";
    wndclassx.lpszMenuName = nullptr;
    wndclassx.hIconSm = 0;

    if (!RegisterClassEx(&wndclassx)) return 0;

    HWND hWnd = CreateWindow(L"WndProc", L"WM_MENUCHAR", WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hInstance, 0);

    ShowWindow(hWnd, SW_MAXIMIZE);
    UpdateWindow(hWnd);

    MSG msg;
    while (GetMessage(&msg, 0, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (int)msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_MENUCHAR:
        return MAKELPARAM(5, MNC_SELECT);

        case WM_DESTROY:
        PostQuitMessage(0);
        break;

        default:
        return DefWindowProc(hwnd, message, wParam, lParam);
    }
    return 0;
}

MNC_SELECT仅“选择”由低位字指定的菜单项,即,如果您可以看到菜单项将突出显示的菜单。 看起来毫无意义,不确定用例是什么。 如果您想实际调用菜单项,则可以使用MNC_EXECUTE。

此外,在WM_MENUCHAR消息的lParam中返回的默认“系统菜单”显然只有一个项目 - 一个用于激活实际系统菜单。 在实际的系统菜单中,“最大化”和“关闭”之间的分隔符计为菜单项,因此“关闭”菜单项的序号实际为6.因此,此代码将执行以下操作:如果按Alt + A并保持按住Alt,它会弹出窗口系统菜单。 如果再按A键,它将关闭窗口。

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int count = 0;
    switch (message)
    {
    case WM_MENUCHAR:
        count = GetMenuItemCount((HMENU)lParam);
        if (count == 1)
            return MAKELRESULT(0, MNC_EXECUTE);
        else
            return MAKELRESULT(6, MNC_EXECUTE);

    case WM_DESTROY:
        PostQuitMessage(0);
        break;

    default:
        return DefWindowProc(hwnd, message, wParam, lParam);
    }
    return 0;
}

我认为以下内容显示了消息的完整用途,包括MNC_SELECT和MNC_EXECUTE。 如果您按住Alt并按住A键,它将弹出系统菜单并从上到下突出显示它上面的每个项目,直到它到达最后一个项目(通常是“关闭”)然后执行。 注意当突出显示“最大化”和突出显示“关闭”时,它会“选择”分隔符。

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int count = 0;
    static int selected = 1;
    switch (message)
    {
    case WM_MENUCHAR:
        count = GetMenuItemCount((HMENU)lParam);
        if (count == 1)
            return MAKELRESULT(0, MNC_EXECUTE);
        else
        {
            if (selected < count)
                return MAKELRESULT(selected++, MNC_SELECT);
            else
                return MAKELRESULT(count - 1, MNC_EXECUTE);
        }

    case WM_DESTROY:
        PostQuitMessage(0);
        break;

    default:
        return DefWindowProc(hwnd, message, wParam, lParam);
    }
    return 0;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM