1
votes

I've recently started teaching myself WinAPI, so bear with me here.

Compiler: TDM-GCC 4.9.2
OS: Windows 8.1 64-bit

I've recently learned how to create menus using resources. In regards to that, I've noticed something odd about handling the WM_COMMAND message for menus. The MSDN documentation tells me that if I want to handle a message sent from a menu, the command item ID can be found in the low word of WPARAM; so I assumed that the code in my window procedure would look like this:

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;
}

However, I noticed that the command items in the menu weren't working. After some debugging, I figured out that wParam was always 0 and my IDs were actually in lParam! I made the quick change to the following code:

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

    break;
}

And it works!

My question: why?
How come the documentation says it's in wParam when for me it's in lParam?

Also, here are my resource.rc and resource.h files in case it helps:

"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



Edit 7/23/15:
SOLVED. My window procedure had the wrong signature. Can't believe it was something so trivial! Thanks, cremno!
2

2 Answers

5
votes

The WPARAM and LPARAM parameter are not in the correct order in your code:

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

From the WindowProc callback function MSDN documentation:

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

Just swap them to fix your code:

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

Your WM_COMMAND message handling should check the high-order WORD of wParam first. Because this value tells you if it is a Menu, Accelerator or child control which is sending the message.

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

See the table on the MSDN documentation: WM_COMMAND message