2 * Unit tests for window message handling
4 * Copyright 1999 Ove Kaaven
5 * Copyright 2003 Dimitrie O. Paun
6 * Copyright 2004 Dmitry Timoshkov
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 #include "wine/test.h"
37 FIXME: add tests for these
38 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
39 WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
40 WS_THICKFRAME: thick border
41 WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
42 WS_BORDER (default for overlapped windows): single black border
43 none (default for child (and popup?) windows): no border
47 sent=0x1, posted=0x2, parent=0x4, wparam=0x8, lparam=0x10,
48 defwinproc=0x20, optional=0x40, hook=0x80
52 UINT message; /* the WM_* code */
53 msg_flags_t flags; /* message props */
54 WPARAM wParam; /* expected value of wParam */
55 LPARAM lParam; /* expected value of lParam */
58 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
59 static const struct message WmCreateOverlappedSeq[] = {
60 { HCBT_CREATEWND, hook },
61 { WM_GETMINMAXINFO, sent },
62 { WM_NCCREATE, sent },
63 { WM_NCCALCSIZE, sent|wparam, 0 },
67 /* ShowWindow (for overlapped window) (16/32) */
68 static const struct message WmShowOverlappedSeq[] = {
69 { WM_SHOWWINDOW, sent|wparam, 1 },
70 { WM_NCPAINT, sent|wparam|optional, 1 },
71 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
72 /* FIXME: WM_QUERYNEWPALETTE, if in 256-color mode */
73 { WM_NCPAINT, sent|wparam|optional, 1 },
74 { WM_GETTEXT, sent|defwinproc|optional },
75 { WM_ERASEBKGND, sent|optional },
76 { HCBT_ACTIVATE, hook },
77 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
78 { WM_ACTIVATEAPP, sent|wparam, 1 },
79 { WM_NCACTIVATE, sent|wparam, 1 },
80 { WM_GETTEXT, sent|defwinproc },
81 { WM_ACTIVATE, sent|wparam, 1 },
82 { HCBT_SETFOCUS, hook },
83 { WM_IME_SETCONTEXT, sent|optional },
84 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
85 { WM_NCPAINT, sent|wparam|optional, 1 },
86 { WM_GETTEXT, sent|defwinproc|optional },
87 { WM_ERASEBKGND, sent|optional },
88 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
94 /* DestroyWindow (for overlapped window) (32) */
95 static const struct message WmDestroyOverlappedSeq[] = {
96 { HCBT_DESTROYWND, hook },
97 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
98 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
99 { WM_NCACTIVATE, sent|wparam, 0 },
100 { WM_ACTIVATE, sent|wparam, 0 },
101 { WM_ACTIVATEAPP, sent|wparam, 0 },
102 { WM_KILLFOCUS, sent|wparam, 0 },
103 { WM_IME_SETCONTEXT, sent|optional },
104 { WM_DESTROY, sent },
105 { WM_NCDESTROY, sent },
108 /* CreateWindow (for child window, not initially visible) */
109 static const struct message WmCreateChildSeq[] = {
110 { HCBT_CREATEWND, hook },
111 { WM_NCCREATE, sent },
112 /* child is inserted into parent's child list after WM_NCCREATE returns */
113 { WM_NCCALCSIZE, sent|wparam, 0 },
117 { WM_PARENTNOTIFY, sent|parent|wparam, 1 },
120 /* ShowWindow (for child window) */
121 static const struct message WmShowChildSeq[] = {
122 { WM_SHOWWINDOW, sent|wparam, 1 },
123 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
124 { WM_ERASEBKGND, sent|parent|optional },
125 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
128 /* DestroyWindow (for child window) */
129 static const struct message WmDestroyChildSeq[] = {
130 { HCBT_DESTROYWND, hook },
131 { WM_PARENTNOTIFY, sent|parent|wparam, 2 },
132 { WM_SHOWWINDOW, sent|wparam, 0 },
133 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
134 { WM_ERASEBKGND, sent|parent|optional },
135 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
136 { HCBT_SETFOCUS, hook }, /* set focus to a parent */
137 { WM_KILLFOCUS, sent },
138 { WM_IME_SETCONTEXT, sent|optional },
139 { WM_DESTROY, sent },
140 { WM_DESTROY, sent|optional }, /* a bug in win2k sp4 ? */
141 { WM_NCDESTROY, sent },
142 { WM_NCDESTROY, sent|optional }, /* a bug in win2k sp4 ? */
145 /* Moving the mouse in nonclient area */
146 static const struct message WmMouseMoveInNonClientAreaSeq[] = { /* FIXME: add */
147 { WM_NCHITTEST, sent },
148 { WM_SETCURSOR, sent },
149 { WM_NCMOUSEMOVE, posted },
152 /* Moving the mouse in client area */
153 static const struct message WmMouseMoveInClientAreaSeq[] = { /* FIXME: add */
154 { WM_NCHITTEST, sent },
155 { WM_SETCURSOR, sent },
156 { WM_MOUSEMOVE, posted },
159 /* Moving by dragging the title bar (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
160 static const struct message WmDragTitleBarSeq[] = { /* FIXME: add */
161 { WM_NCLBUTTONDOWN, sent|wparam, HTCAPTION },
162 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_MOVE+2 },
163 { WM_GETMINMAXINFO, sent|defwinproc },
164 { WM_ENTERSIZEMOVE, sent|defwinproc },
165 { WM_WINDOWPOSCHANGING, sent|defwinproc },
166 { WM_WINDOWPOSCHANGED, sent|defwinproc },
167 { WM_MOVE, sent|defwinproc },
168 { WM_EXITSIZEMOVE, sent|defwinproc },
171 /* Sizing by dragging the thick borders (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
172 static const struct message WmDragThickBordersBarSeq[] = { /* FIXME: add */
173 { WM_NCLBUTTONDOWN, sent|wparam, 0xd },
174 { WM_SYSCOMMAND, sent|defwinproc|wparam, 0xf004 },
175 { WM_GETMINMAXINFO, sent|defwinproc },
176 { WM_ENTERSIZEMOVE, sent|defwinproc },
177 { WM_SIZING, sent|defwinproc|wparam, 4}, /* one for each mouse movement */
178 { WM_WINDOWPOSCHANGING, sent|defwinproc },
179 { WM_GETMINMAXINFO, sent|defwinproc },
180 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
181 { WM_NCPAINT, sent|defwinproc|wparam, 1 },
182 { WM_GETTEXT, sent|defwinproc },
183 { WM_ERASEBKGND, sent|defwinproc },
184 { WM_WINDOWPOSCHANGED, sent|defwinproc },
185 { WM_MOVE, sent|defwinproc },
186 { WM_SIZE, sent|defwinproc },
187 { WM_EXITSIZEMOVE, sent|defwinproc },
190 /* Resizing child window with MoveWindow (32) */
191 static const struct message WmResizingChildWithMoveWindowSeq[] = {
192 { WM_WINDOWPOSCHANGING, sent },
193 { WM_NCCALCSIZE, sent|wparam, 1 },
194 { WM_ERASEBKGND, sent|optional },
195 { WM_WINDOWPOSCHANGED, sent },
196 { WM_MOVE, sent|defwinproc },
197 { WM_SIZE, sent|defwinproc },
200 /* Clicking on inactive button */
201 static const struct message WmClickInactiveButtonSeq[] = { /* FIXME: add */
202 { WM_NCHITTEST, sent },
203 { WM_PARENTNOTIFY, sent|parent|wparam, WM_LBUTTONDOWN },
204 { WM_MOUSEACTIVATE, sent },
205 { WM_MOUSEACTIVATE, sent|parent|defwinproc },
206 { WM_SETCURSOR, sent },
207 { WM_SETCURSOR, sent|parent|defwinproc },
208 { WM_LBUTTONDOWN, posted },
209 { WM_KILLFOCUS, posted|parent },
210 { WM_SETFOCUS, posted },
211 { WM_CTLCOLORBTN, posted|parent },
212 { BM_SETSTATE, posted },
213 { WM_CTLCOLORBTN, posted|parent },
214 { WM_LBUTTONUP, posted },
215 { BM_SETSTATE, posted },
216 { WM_CTLCOLORBTN, posted|parent },
217 { WM_COMMAND, posted|parent },
220 /* Reparenting a button (16/32) */
221 /* The last child (button) reparented gets topmost for its new parent. */
222 static const struct message WmReparentButtonSeq[] = { /* FIXME: add */
223 { WM_SHOWWINDOW, sent|wparam, 0 },
224 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER },
225 { WM_ERASEBKGND, sent|parent },
226 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER },
227 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOZORDER },
228 { WM_CHILDACTIVATE, sent },
229 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW|SWP_NOZORDER },
230 { WM_MOVE, sent|defwinproc },
231 { WM_SHOWWINDOW, sent|wparam, 1 },
234 /* Creation of a modal dialog (32) */
235 static const struct message WmCreateModalDialogSeq[] = { /* FIXME: add */
236 { WM_CANCELMODE, sent|parent },
237 { WM_KILLFOCUS, sent|parent },
238 { WM_ENABLE, sent|parent|wparam, 0 },
239 /* (window proc creation messages not tracked yet, because...) */
240 { WM_SETFONT, sent },
241 { WM_INITDIALOG, sent },
242 /* (...the window proc message hook was installed here, IsVisible still FALSE) */
243 { WM_NCACTIVATE, sent|parent|wparam, 0 },
244 { WM_GETTEXT, sent|defwinproc },
245 { WM_ACTIVATE, sent|parent|wparam, 0 },
246 { WM_WINDOWPOSCHANGING, sent },
247 { WM_WINDOWPOSCHANGING, sent|parent },
248 { WM_NCACTIVATE, sent|wparam, 1 },
249 { WM_ACTIVATE, sent|wparam, 1 },
250 /* (setting focus) */
251 { WM_SHOWWINDOW, sent|wparam, 1 },
252 { WM_WINDOWPOSCHANGING, sent },
253 { WM_NCPAINT, sent },
254 { WM_GETTEXT, sent|defwinproc },
255 { WM_ERASEBKGND, sent },
256 { WM_CTLCOLORDLG, sent|defwinproc },
257 { WM_WINDOWPOSCHANGED, sent },
259 /* FIXME: (bunch of WM_CTLCOLOR* for each control) */
260 { WM_PAINT, sent|parent },
261 { WM_ENTERIDLE, sent|parent|wparam, 0},
262 { WM_SETCURSOR, sent|parent },
265 /* Destruction of a modal dialog (32) */
266 static const struct message WmDestroyModalDialogSeq[] = { /* FIXME: add */
267 /* (inside dialog proc: EndDialog is called) */
268 { WM_ENABLE, sent|parent|wparam, 1 },
269 { WM_SETFOCUS, sent },
270 { WM_WINDOWPOSCHANGING, sent },
271 { WM_NCPAINT, sent|parent },
272 { WM_GETTEXT, sent|defwinproc },
273 { WM_ERASEBKGND, sent|parent },
274 { WM_WINDOWPOSCHANGED, sent },
275 { WM_NCACTIVATE, sent|wparam, 0 },
276 { WM_ACTIVATE, sent|wparam, 0 },
277 { WM_WINDOWPOSCHANGING, sent },
278 { WM_WINDOWPOSCHANGING, sent|parent },
279 { WM_NCACTIVATE, sent|parent|wparam, 1 },
280 { WM_GETTEXT, sent|defwinproc },
281 { WM_ACTIVATE, sent|parent|wparam, 1 },
282 { WM_KILLFOCUS, sent },
283 { WM_SETFOCUS, sent|parent },
284 { WM_DESTROY, sent },
285 { WM_NCDESTROY, sent },
288 /* Creation of a modal dialog that is resized inside WM_INITDIALOG (32) */
289 static const struct message WmCreateModalDialogResizeSeq[] = { /* FIXME: add */
290 /* (inside dialog proc, handling WM_INITDIALOG) */
291 { WM_WINDOWPOSCHANGING, sent },
292 { WM_NCCALCSIZE, sent },
293 { WM_NCACTIVATE, sent|parent|wparam, 0 },
294 { WM_GETTEXT, sent|defwinproc },
295 { WM_ACTIVATE, sent|parent|wparam, 0 },
296 { WM_WINDOWPOSCHANGING, sent },
297 { WM_WINDOWPOSCHANGING, sent|parent },
298 { WM_NCACTIVATE, sent|wparam, 1 },
299 { WM_ACTIVATE, sent|wparam, 1 },
300 { WM_WINDOWPOSCHANGED, sent },
301 { WM_SIZE, sent|defwinproc },
302 /* (setting focus) */
303 { WM_SHOWWINDOW, sent|wparam, 1 },
304 { WM_WINDOWPOSCHANGING, sent },
305 { WM_NCPAINT, sent },
306 { WM_GETTEXT, sent|defwinproc },
307 { WM_ERASEBKGND, sent },
308 { WM_CTLCOLORDLG, sent|defwinproc },
309 { WM_WINDOWPOSCHANGED, sent },
311 /* (bunch of WM_CTLCOLOR* for each control) */
312 { WM_PAINT, sent|parent },
313 { WM_ENTERIDLE, sent|parent|wparam, 0 },
314 { WM_SETCURSOR, sent|parent },
317 /* SetMenu for NonVisible windows with size change*/
318 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
319 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
320 { WM_NCCALCSIZE, sent|wparam, 1 },
321 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
326 /* SetMenu for NonVisible windows with no size change */
327 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
328 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
329 { WM_NCCALCSIZE, sent|wparam, 1 },
330 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
333 /* SetMenu for Visible windows with size change */
334 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
335 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
336 { WM_NCCALCSIZE, sent|wparam, 1 },
337 { WM_NCPAINT, sent|wparam, 1 },
338 { WM_GETTEXT, sent },
339 { WM_ERASEBKGND, sent|optional },
340 { WM_ACTIVATE, sent|optional },
341 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
346 /* SetMenu for Visible windows with no size change */
347 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
348 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
349 { WM_NCCALCSIZE, sent|wparam, 1 },
350 { WM_NCPAINT, sent|wparam, 1 },
351 { WM_GETTEXT, sent },
352 { WM_ERASEBKGND, sent|optional },
353 { WM_ACTIVATE, sent|optional },
354 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
358 static int sequence_cnt, sequence_size;
359 static struct message* sequence;
361 static void add_message(const struct message *msg)
366 sequence = malloc ( sequence_size * sizeof (struct message) );
368 if (sequence_cnt == sequence_size)
371 sequence = realloc ( sequence, sequence_size * sizeof (struct message) );
375 sequence[sequence_cnt].message = msg->message;
376 sequence[sequence_cnt].flags = msg->flags;
377 sequence[sequence_cnt].wParam = msg->wParam;
378 sequence[sequence_cnt].lParam = msg->lParam;
383 static void flush_sequence()
387 sequence_cnt = sequence_size = 0;
390 static void ok_sequence(const struct message *expected, const char *context)
392 static const struct message end_of_sequence = { 0, 0, 0, 0 };
393 const struct message *actual = sequence;
395 add_message(&end_of_sequence);
397 while (expected->message && actual->message)
399 trace("expected %04x - actual %04x\n", expected->message, actual->message);
401 if (expected->message == actual->message)
403 if (expected->flags & wparam)
404 ok (expected->wParam == actual->wParam,
405 "%s: in msg 0x%04x expecting wParam 0x%x got 0x%x\n",
406 context, expected->message, expected->wParam, actual->wParam);
407 if (expected->flags & lparam)
408 ok (expected->lParam == actual->lParam,
409 "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
410 context, expected->message, expected->lParam, actual->lParam);
411 /* FIXME: should we check defwinproc? */
412 ok ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
413 "%s: the msg 0x%04x should have been %s\n",
414 context, expected->message, (expected->flags & posted) ? "posted" : "sent");
415 ok ((expected->flags & parent) == (actual->flags & parent),
416 "%s: the msg 0x%04x was expected in %s\n",
417 context, expected->message, (expected->flags & parent) ? "parent" : "child");
418 ok ((expected->flags & hook) == (actual->flags & hook),
419 "%s: the msg 0x%04x should have been hooked\n",
420 context, expected->message);
424 else if (expected->flags & optional)
429 ok (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
430 context, expected->message, actual->message);
438 if (expected->message || actual->message)
439 ok (FALSE, "%s: the msg sequence is not complete\n", context);
445 /* test if we receive the right sequence of messages */
446 static void test_messages(void)
448 HWND hwnd, hparent, hchild;
449 HWND hchild2, hbutton;
452 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
453 100, 100, 200, 200, 0, 0, 0, NULL);
454 ok (hwnd != 0, "Failed to create overlapped window\n");
455 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped");
457 ShowWindow(hwnd, TRUE);
458 ok_sequence(WmShowOverlappedSeq, "ShowWindow:overlapped");
461 ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped");
463 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
464 100, 100, 200, 200, 0, 0, 0, NULL);
465 ok (hparent != 0, "Failed to create parent window\n");
468 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILDWINDOW,
469 0, 0, 10, 10, hparent, 0, 0, NULL);
470 ok (hchild != 0, "Failed to create child window\n");
471 ok_sequence(WmCreateChildSeq, "CreateWindow:child");
473 hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILDWINDOW,
474 100, 100, 50, 50, hparent, 0, 0, NULL);
475 ok (hchild2 != 0, "Failed to create child2 window\n");
478 hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILDWINDOW,
479 0, 100, 50, 50, hchild, 0, 0, NULL);
480 ok (hbutton != 0, "Failed to create button window\n");
483 ShowWindow(hchild, TRUE);
484 ok_sequence(WmShowChildSeq, "ShowWindow:child");
489 MoveWindow(hchild, 10, 10, 20, 20, TRUE);
490 ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child");
492 DestroyWindow(hchild);
493 ok_sequence(WmDestroyChildSeq, "DestroyWindow:child");
494 DestroyWindow(hchild2);
495 DestroyWindow(hbutton);
496 DestroyWindow(hparent);
499 /* Message sequence for SetMenu */
500 hmenu = CreateMenu();
501 ok (hmenu != 0, "Failed to create menu\n");
502 ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
503 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
504 100, 100, 200, 200, 0, hmenu, 0, NULL);
505 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped");
506 ok (SetMenu(hwnd, 0), "SetMenu");
507 ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange");
508 ok (SetMenu(hwnd, 0), "SetMenu");
509 ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange");
510 ShowWindow(hwnd, TRUE);
512 ok (SetMenu(hwnd, 0), "SetMenu");
513 ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange");
514 ok (SetMenu(hwnd, hmenu), "SetMenu");
515 ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange");
520 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
524 trace("%p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
526 msg.message = message;
527 msg.flags = sent|wparam|lparam;
532 return DefWindowProcA(hwnd, message, wParam, lParam);
535 static BOOL RegisterWindowClasses(void)
540 cls.lpfnWndProc = MsgCheckProcA;
543 cls.hInstance = GetModuleHandleA(0);
545 cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
546 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
547 cls.lpszMenuName = NULL;
548 cls.lpszClassName = "TestWindowClass";
550 if(!RegisterClassA(&cls)) return FALSE;
553 cls.lpfnWndProc = DefWindowProcA;
556 cls.hInstance = GetModuleHandleA(0);
558 cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
559 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
560 cls.lpszMenuName = NULL;
561 cls.lpszClassName = "TestParentClass";
563 if(!RegisterClassA(&cls)) return FALSE;
566 cls.lpfnWndProc = DefWindowProcA;
569 cls.hInstance = GetModuleHandleA(0);
571 cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
572 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
573 cls.lpszMenuName = NULL;
574 cls.lpszClassName = "SimpleWindowClass";
576 if(!RegisterClassA(&cls)) return FALSE;
581 static HHOOK hCBT_hook;
583 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
587 trace("CBT: %d, %08x, %08lx\n", nCode, wParam, lParam);
589 if (GetClassNameA((HWND)wParam, buf, sizeof(buf)))
591 if (!strcmp(buf, "TestWindowClass") ||
592 !strcmp(buf, "TestParentClass") ||
593 !strcmp(buf, "SimpleWindowClass"))
604 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
609 if (!RegisterWindowClasses()) assert(0);
611 hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
616 UnhookWindowsHookEx(hCBT_hook);