WM_COMMAND, HWND, CreateWindow .. etc

Hi, and thanks for the support!

I am "fairly" new at win32 api programming and have spent this night going over a basic scratch for an application I wanna write. Basically a simple GUI debugger. Get the process and send a debug event signal, that's it.

After struggling for multiple hours on just the very basic stuff such as WM_COMMAND and even and more importantly where to place variables which will be shared by multiple functions, such as the HWND for all my control boxes such as ListView. After a while I stopped thinking and programming, and just started pasting code all over the place.
So for the people who have the time, could you go over this short code snippet and give me some remarks on how to program this better? Thank you.

It probably burns to read.. I know..

One of the important questions is actually where to put my variables.. As you can see some of the HWND variables are redefined multiple places. In a hack'n'patch attempt to get it running.. Or scratch that, the entire code up to this point is a hack'n'patch attempt to just get it running :)

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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	PAINTSTRUCT ps;
	HDC hdc;
	TCHAR greeting[] = _T("Hello, World!");

	HMENU hMenu, hSubMenu;
	HICON hIcon, hIconSm;

	HINSTANCE hInstance = GethInstance(hWnd);

	HWND hWndLeft;
	HWND hWndMain;

	switch (message)
	{
	case WM_CREATE:
	{
		hMenu = CreateMenu();
		hSubMenu = CreatePopupMenu();
		AppendMenu(hSubMenu, MF_STRING, ID_FILE_COMMANDLINE, "&Get Processes");
		AppendMenu(hSubMenu, MF_STRING, ID_FILE_EXIT, "E&xit");
		AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "&File");

		hSubMenu = CreatePopupMenu();
		AppendMenu(hSubMenu, MF_STRING, ID_FILE_HELP, "&Help");
		AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "&Help");
		SetMenu(hWnd, hMenu);

		HWND hWndLeft = CreateListView(hWnd, hInstance, 1);
		if (hWndLeft == NULL)
		{
			//MessageBox(hWnd, "hWndLeft failed to create", "hWndLeft", 0);
		}
		HWND hWndMain = CreateListViewMain(hWnd, hInstance, 1);
		if (hWndMain == NULL)
		{
			//MessageBox(hWnd, "hWndMain failed to create", "hWndMain", 0);
		}

		break;
	}
	case WM_SIZE:
	{
		if (wParam == SIZE_MAXIMIZED)
		{
			HWND hWndLeft = CreateListView(hWnd, hInstance, 2);
			if (hWndLeft == NULL)
			{
				MessageBox(hWnd, "hWndLeft failed to create", "hWndLeft", 0);
			}
			HWND hWndMain = CreateListViewMain(hWnd, hInstance, 2);
			if (hWndMain == NULL)
			{
				MessageBox(hWnd, "hWndMain failed to create", "hWndMain", 0);
			}
		}
		if (wParam == SIZE_MINIMIZED)
		{
			HWND hWndLeft = CreateListView(hWnd, hInstance, 1);
			if (hWndLeft == NULL)
			{
				MessageBox(hWnd, "hWndLeft failed to create", "hWndLeft", 0);
			}
			HWND hWndMain = CreateListViewMain(hWnd, hInstance, 1);
			if (hWndMain == NULL)
			{
				MessageBox(hWnd, "hWndMain failed to create", "hWndMain", 0);
			}
		}
		break;
	}

	case WM_COMMAND:
		switch (LOWORD(wParam))
		{
		case ID_FILE_EXIT:
			PostMessage(hWnd, WM_CLOSE, 0, 0);
			break;
		case ID_FILE_HELP:
			MessageBox(hWnd, "Simple file debugger - test/debug version", "Debugger Help - win32", NULL);
			break;
		case ID_FILE_COMMANDLINE:
			hWndLeft = CreateListView(hWnd, hInstance, 1);
			if (!InsertListViewItem(hWndLeft) || (hWndLeft == NULL))
			{
				if (hWndLeft == NULL)
				{
					MessageBox(NULL, "HWND is NULL. Could not set InsertListFileViewItem()", "InsertLiftFileViewItem()", 0);
				}
				else
				{
					MessageBox(NULL, "InsertListFileViewItem() failed", "InsertLiftFileViewItem()", 0);
				}
			}

			break;

	return 0;
}


BOOL InsertListViewItem(HWND hWndListView)
{
	LVITEM lvI;
	HANDLE hProcessSnap;
	HANDLE hProcess;
	PROCESSENTRY32 pe32;
	DWORD dwPriorityClass;

	// Take a snapshot of all processes in the system.
	hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	if (hProcessSnap == INVALID_HANDLE_VALUE)
	{
		printError(TEXT("CreateToolhelp32Snapshot (of processes)"));
		return(FALSE);
	}

	// Set the size of the structure before using it.
	pe32.dwSize = sizeof(PROCESSENTRY32);

	// Retrieve information about the first process,
	// and exit if unsuccessful
	if (!Process32First(hProcessSnap, &pe32))
	{
		printError(TEXT("Process32First")); // show cause of failure
		CloseHandle(hProcessSnap);          // clean the snapshot object
		return(FALSE);
	}

	// Now walk the snapshot of processes, and
	// display information about each process in turn
	do
	{
		lvI.pszText = pe32.szExeFile;
		lvI.mask = LVIF_TEXT | LVIF_STATE;
		lvI.iSubItem = 0;
		lvI.state = 0;
		lvI.stateMask = 0;
		lvI.iItem = ListView_GetItemCount(hWndListView) + 1;

		int Index = ListView_InsertItem(hWndListView, &lvI);
		if (Index == -1)
		{
			MessageBox(NULL, "Failed to insert listview item", "InsertListViewItem()", 0);
		}

	} while (Process32Next(hProcessSnap, &pe32));

	CloseHandle(hProcessSnap);
	return true;
}

HWND CreateListView(HWND hWndParent, HINSTANCE hInst, int flags)
{
	INITCOMMONCONTROLSEX icex;
	icex.dwICC = ICC_LISTVIEW_CLASSES;
	InitCommonControlsEx(&icex);
	HWND hWndListView = NULL;

	RECT rcClient;
	GetClientRect(hWndParent, &rcClient);

	if (flags == 1) {
		hWndListView = CreateWindow(WC_LISTVIEW, "listviewleft", WS_CHILD | WS_VISIBLE | WS_BORDER | LVS_LIST | LVS_EDITLABELS | CS_HREDRAW | CS_VREDRAW,
			0, 0, (rcClient.right / 3),
			rcClient.bottom-20, hWndParent, (HMENU)IDM_LISTVIEW_LEFT, hInst, NULL);
	//	ListView_SetBkColor(hWndListView, BACKGROUND_BLUE);
	}
	else if (flags == 2)
	{
		hWndListView = CreateWindow(WC_LISTVIEW, "listviewleft", WS_CHILD | WS_VISIBLE | WS_BORDER | LVS_LIST | LVS_EDITLABELS | CS_HREDRAW | CS_VREDRAW,
			0, 0, (rcClient.right / 6),
			rcClient.bottom, hWndParent, (HMENU)IDM_LISTVIEW_LEFT, hInst, NULL);
		//ListView_SetBkColor(hWndListView, BACKGROUND_BLUE);
	}
	else
	{
		MessageBox(hWndParent, "Wrong flag in CreateListViewLeft()!", "CreateListViewLeft()", NULL);
		hWndListView = NULL;
	}

	if (!hWndListView)
	{
		MessageBox(NULL,
			_T("Call to CreateWindow failed!"),
			_T("Win32 Guided Tour"),
			NULL);

		hWndListView = NULL;
	}

	return hWndListView;
}

HWND CreateListViewMain(HWND hWndParent, HINSTANCE hInst, int flags)
{
	INITCOMMONCONTROLSEX icex;
	icex.dwICC = ICC_LISTVIEW_CLASSES;
	InitCommonControlsEx(&icex);
	HWND hWndListView = NULL;

	RECT rcClient;
	GetClientRect(hWndParent, &rcClient);

	if (flags == 1)
	{
		hWndListView = CreateWindow(WC_LISTVIEW, "listviewmain", WS_CHILD | WS_BORDER | LVS_LIST | LVS_EDITLABELS | WS_VISIBLE | CS_HREDRAW | CS_VREDRAW,
			(rcClient.right / 3), 0, (rcClient.right - (rcClient.right / 3) - 0.2), (rcClient.bottom - rcClient.top) - 20, hWndParent, (HMENU)IDM_LISTVIEW_MAIN, hInst, NULL);
		//ListView_SetBkColor(hWndListView, BACKGROUND_BLUE);
	}
	else if (flags == 2)
	{
		hWndListView = CreateWindow(WC_LISTVIEW, "listviewmain", WS_CHILD | WS_BORDER | LVS_LIST | LVS_EDITLABELS | WS_VISIBLE | CS_HREDRAW | CS_VREDRAW,
			(rcClient.right / 6), 0, (rcClient.right - (rcClient.right / 6)), (rcClient.bottom - rcClient.top), hWndParent, (HMENU)IDM_LISTVIEW_MAIN, hInst, NULL);
		//ListView_SetBkColor(hWndListView, BACKGROUND_BLUE);
	}
	else
	{
		MessageBox(hWndParent, "Wrong flag in CreateListViewMain()!", "CreateListViewMain()", NULL);
		hWndListView = NULL;
	}

	if (!hWndListView)
	{
		MessageBox(NULL,
			_T("Call to CreateWindow failed!"),
			_T("Win32 Guided Tour"),
			NULL);

		hWndListView = NULL;
	}

	return hWndListView;
}
Last edited on
You create far to many windows and create memory leaks. The only place to create them is in WM_CREATE. You can keep your hWndLeft and hWndRight in your WndProc and pass them to the functions which need them.

In many books and tutorials the window handles are somewhere outside WinMain which makes them global which is not good - though in a simple app like yours that should be not a problem.

BTW. Why don't you create the menu in the resource editor?
Thank you for the help. Think I managed to fix the window creation problem, but not exactly sure where to place the window handles.

I had some initial problems with the resource editor but it's all fixed now and the menu and dialog items will be placed there from now on.
Last edited on
Only spent a second looking at your code but the scoping of HWNDs is something all newcomers to Win32 get wrong. They absolutely never need to be globals. The deal is simply this...

When you create controls with CreateWindow() or CreateWindowEx() the HMENU parameter serves dual purpose as a control id. That's simply a number you assign globally such as this...

#define ID_COMMAND_BUTTON_1 2000

You can leave you HWNDs go out of scope. In fact, in many cases you don't even need to assign them at creation time, and can even sdo this...

CreateWindowEx(......);

But, you can always get the HWND of the object through the GetDlgItem() function. All you need is the control's parent and the control id as previously described.

I personally hasve not used and global variables in my Win32 GUI programs for years. Windows keeps track of it all, and you can get whatever info you need from functipons such as GetDlgItem().
Holy s* Freddie, thank you. That definitely helped!..
Topic archived. No new replies allowed.