簡體   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