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 LRESULT WINAPI
ParentMsgCheckProcA(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
539 trace("%p, %04x, %08x, %08lx\n", hwnd
, message
, wParam
, lParam
);
541 if (message
== WM_PARENTNOTIFY
)
543 msg
.message
= message
;
544 msg
.flags
= sent
|parent
|wparam
|lparam
;
550 return DefWindowProcA(hwnd
, message
, wParam
, lParam
);
553 static BOOL
RegisterWindowClasses(void)
558 cls
.lpfnWndProc
= MsgCheckProcA
;
561 cls
.hInstance
= GetModuleHandleA(0);
563 cls
.hCursor
= LoadCursorA(0, (LPSTR
)IDC_ARROW
);
564 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
565 cls
.lpszMenuName
= NULL
;
566 cls
.lpszClassName
= "TestWindowClass";
568 if(!RegisterClassA(&cls
)) return FALSE
;
571 cls
.lpfnWndProc
= ParentMsgCheckProcA
;
574 cls
.hInstance
= GetModuleHandleA(0);
576 cls
.hCursor
= LoadCursorA(0, (LPSTR
)IDC_ARROW
);
577 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
578 cls
.lpszMenuName
= NULL
;
579 cls
.lpszClassName
= "TestParentClass";
581 if(!RegisterClassA(&cls
)) return FALSE
;
584 cls
.lpfnWndProc
= DefWindowProcA
;
587 cls
.hInstance
= GetModuleHandleA(0);
589 cls
.hCursor
= LoadCursorA(0, (LPSTR
)IDC_ARROW
);
590 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
591 cls
.lpszMenuName
= NULL
;
592 cls
.lpszClassName
= "SimpleWindowClass";
594 if(!RegisterClassA(&cls
)) return FALSE
;
599 static HHOOK hCBT_hook
;
601 static LRESULT CALLBACK
cbt_hook_proc(int nCode
, WPARAM wParam
, LPARAM lParam
)
605 trace("CBT: %d, %08x, %08lx\n", nCode
, wParam
, lParam
);
607 if (GetClassNameA((HWND
)wParam
, buf
, sizeof(buf
)))
609 if (!strcmp(buf
, "TestWindowClass") ||
610 !strcmp(buf
, "TestParentClass") ||
611 !strcmp(buf
, "SimpleWindowClass"))
622 return CallNextHookEx(hCBT_hook
, nCode
, wParam
, lParam
);
627 if (!RegisterWindowClasses()) assert(0);
629 hCBT_hook
= SetWindowsHookExA(WH_CBT
, cbt_hook_proc
, 0, GetCurrentThreadId());
634 UnhookWindowsHookEx(hCBT_hook
);