Designing Menus: Problem assigning events to menu item clicks

First, here my code: (Compiled as C)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include <windows.h>

#define ID_FILE_EXIT 4001
#define ID_STUFF_GO  4002
#define ID_HELP_WTF  4003

#define WM_MYMESSAGE 4004

const char g_szClassName[] = "myWindowClass";

// Step 4: the Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
		case WM_MYMESSAGE:
			MessageBox(hwnd, "", "", MB_OK);
		break;
		case WM_CREATE:
			{
			HMENU hMenu, hSubMenu;
			HICON hIcon, hIconSm;

			hMenu = CreateMenu();

			hSubMenu = CreatePopupMenu();
			AppendMenu(hSubMenu, MF_STRING, ID_FILE_EXIT, "&Exit");
			AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "&File");

			hSubMenu = CreatePopupMenu();
			AppendMenu(hSubMenu, MF_STRING, ID_STUFF_GO, "&Go");
			AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "&Stuff");

			hMyMenu = CreatePopupMenu();
			AppendMenu(hSubMenu, MF_STRING, ID_HELP_WTF, "&Wtf is this program for?");
			AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "&Help");

			SetMenu(hwnd, hMenu);

			hIcon = LoadImage(NULL, "my_icon.ico", IMAGE_ICON, 32, 32, LR_LOADFROMFILE);
			if (hIcon)
				SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
			else
				MessageBox(hwnd, "File not found: my_icon.ico", "ERROR", MB_OK | MB_ICONERROR);

			hIconSm = LoadImage(NULL, "my_icon.ico", IMAGE_ICON, 16, 16, LR_LOADFROMFILE);
			if (hIconSm)
				SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIconSm);
			else
				MessageBox(hwnd, "Failed to load small icon", "ERROR", MB_OK | MB_ICONERROR);
			}
		break;
		case WM_COMMAND:
			{
			switch (LOWORD(wParam))
				case ID_FILE_EXIT:
					{
						MessageBox(hwnd, "Bye!", "", MB_OK);
						PostMessage(hwnd, WM_CLOSE, 0, 0);
					}
				break;
				case ID_STUFF_GO:
					{
						PostMessage(hwnd, WM_MYMESSAGE, 0, 0);
					}
				break;
				case ID_HELP_WTF:
					{
						MessageBox(hwnd, "Your guess is as good as mine :)", "", MB_OK);
					}
				break;
			}
			break;
		case WM_LBUTTONDOWN:
			{
			char szFileName[MAX_PATH];
			HINSTANCE hInstance = GetModuleHandle(NULL);
			
			GetModuleFileName(hInstance, szFileName, MAX_PATH);
			MessageBox(hwnd, szFileName, "Executable Name:", MB_OK);
			}
		break;
		case WM_CLOSE:
            DestroyWindow(hwnd);
        break;
        case WM_DESTROY:
            PostQuitMessage(0);
        break;
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wc;
    HWND hwnd;
    MSG Msg;

    //Step 1: Registering the Window Class
    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = 0;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = g_szClassName;
    wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

    if(!RegisterClassEx(&wc))
    {
        MessageBox(NULL, "Window Registration Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    // Step 2: Creating the Window
    hwnd = CreateWindowEx(
        WS_EX_CLIENTEDGE,
        g_szClassName,
        "The title of my window",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
        NULL, NULL, hInstance, NULL);

    if(hwnd == NULL)
    {
        MessageBox(NULL, "Window Creation Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    // Step 3: The Message Loop
    while(GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    return Msg.wParam;
}


I'm following the Forger's WinAPI tutorial. The exact problem is that although clicking the menu File > Exit sends a message WM_CLOSE and closes the window as expected (following the message box), the 2 events I added for Stuff > Go and Help > Wtf is this program for don't work at all. And I can't understand why.

Last edited on
You didn't enclose your 'switch' statement in a block - so it only will execute the first statement afterward. Therefore you are able to get the first case to work, but the code after it is completely ignored. (Also there's a variable 'hMyMenu' where it should be 'hSubMenu', or this won't even compile).

I would encourage you also to get into the habit of enclosing any logic statement in a block, even if it's just a one-line statement, like this:

if (something) {
DoSomething();
}

It's easier to read and more concise, and if you want to quickly add a second statement later, the brackets are already there anyway. Not to mention FAR easier when looking for errors/debugging in a large program.


Last edited on
What he's saying is that after your "case WM_COMMAND" statement, you have to have a switch statment, so it would look like this...

1
2
3
4
5
case WM_COMMAND:
switch( LOWORD(wParam) )
{
     other stuff
}


The brackets you have after the WM_COMMAND are superflous.
Last edited on
Thanks, solved.
Topic archived. No new replies allowed.