Меню в WinAPI: я использую LPARAM или WPARAM для WM_COMMAND?

Я недавно начал учить себя WinAPI, так что терпите меня здесь.

Компилятор: TDM-GCC 4.9.2
ОС: Windows 8.1 64-битная

Недавно я научился создавать меню с использованием ресурсов. В связи с этим я заметил кое-что странное в обработке сообщения WM_COMMAND для меню. Документация MSDN говорит мне, что если я хочу обработать сообщение, отправленное из меню, идентификатор элемента команды можно найти в младшем слове WPARAM; поэтому я предположил, что код в моей оконной процедуре будет выглядеть так:

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, LPARAM lParam, WPARAM wParam)
{
    switch (msg)
    {
    case WM_COMMAND:
        switch (LOWORD(wParam))  //<--
        {
        case /*IDs go here*/:

            break;
        }
        break;

    //...
    }

    return 0;
}

Однако я заметил, что пункты команд в меню не работают. После некоторой отладки я обнаружил, что wParam всегда был 0, а мои идентификаторы были в lParam! Я сделал быстрое изменение следующего кода:

switch (lParam)
{
case /*IDs go here*/:

    break;
}

И это работает!

Мой вопрос: почему?
Почему в документации говорится, что она в wParam, а для меня - в lParam?

Также, вот мои файлы resource.rc и resource.h на случай, если это поможет:

"Resource.h":

#define IDR_MYMENU 101

//These are appearing in LPARAM instead of WPARAM
#define ID_FILE_EXIT 9001
#define ID_STUFF_GO  9002

"Resource.rc":

#include "resource.h"

IDR_MYMENU MENU
BEGIN
    POPUP "&File"
    BEGIN
        MENUITEM "E&xit", ID_FILE_EXIT
    END

    POPUP "&Stuff"
    BEGIN
        MENUITEM "&Go", ID_STUFF_GO
        MENUITEM "G&o somewhere else", 0, GRAYED
    END
END



Изменить 23.07.15:
Решаемые. Моя процедура окна имела неправильную подпись. Не могу поверить, что это было так тривиально! Спасибо, кремно!

2 ответа

Решение

Параметры WPARAM и LPARAM находятся в неправильном порядке в вашем коде:

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, LPARAM lParam, WPARAM wParam)

Из функции обратного вызова WindowProc в документации MSDN:

LRESULT CALLBACK WindowProc(
  _In_ HWND   hwnd,
  _In_ UINT   uMsg,
  _In_ WPARAM wParam,
  _In_ LPARAM lParam
);

Просто поменяйте их местами, чтобы исправить ваш код:

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

Ваша обработка сообщений WM_COMMAND должна сначала проверить старшее слово wParam. Потому что это значение указывает, отправляет ли сообщение меню, ускоритель или дочерний элемент управления.

swtich(msg)
{
case WM_COMMAND:
{
    switch(HIWORD(wParam))
    {
        case 0: // Menu
        {
            // Check LOWORD(wParam) here
            break;
        }
    }
    return 0;
}

Смотрите таблицу в документации MSDN: сообщение WM_COMMAND

Другие вопросы по тегам