Fixed some message sequences to succeed on XP.
[wine/multimedia.git] / dlls / user / tests / msg.c
blobd2984a945f8df182158c53b2f9f3c1fdd494313b
1 /*
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
23 #include <assert.h>
24 #include <stdarg.h>
25 #include <stdio.h>
27 #define _WIN32_WINNT 0x0500 /* For WM_CHANGEUISTATE */
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winuser.h"
34 #include "wine/test.h"
36 #define MDI_FIRST_CHILD_ID 2004
39 FIXME: add tests for these
40 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
41 WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
42 WS_THICKFRAME: thick border
43 WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
44 WS_BORDER (default for overlapped windows): single black border
45 none (default for child (and popup?) windows): no border
48 typedef enum {
49 sent=0x1,
50 posted=0x2,
51 parent=0x4,
52 wparam=0x8,
53 lparam=0x10,
54 defwinproc=0x20,
55 beginpaint=0x40,
56 optional=0x80,
57 hook=0x100
58 } msg_flags_t;
60 struct message {
61 UINT message; /* the WM_* code */
62 msg_flags_t flags; /* message props */
63 WPARAM wParam; /* expected value of wParam */
64 LPARAM lParam; /* expected value of lParam */
67 /* Empty message sequence */
68 static const struct message WmEmptySeq[] =
70 { 0 }
72 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
73 static const struct message WmCreateOverlappedSeq[] = {
74 { HCBT_CREATEWND, hook },
75 { WM_GETMINMAXINFO, sent },
76 { WM_NCCREATE, sent },
77 { WM_NCCALCSIZE, sent|wparam, 0 },
78 { WM_CREATE, sent },
79 { 0 }
81 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
82 * for a not visible overlapped window.
84 static const struct message WmSWP_ShowOverlappedSeq[] = {
85 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
86 { WM_NCPAINT, sent|wparam|optional, 1 },
87 { WM_GETTEXT, sent|defwinproc|optional },
88 { WM_ERASEBKGND, sent|optional },
89 { HCBT_ACTIVATE, hook },
90 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
91 { WM_WINDOWPOSCHANGING, sent|wparam|optional, 0 }, /* Win9x: SWP_NOSENDCHANGING */
92 { WM_ACTIVATEAPP, sent|wparam, 1 },
93 { WM_NCACTIVATE, sent|wparam, 1 },
94 { WM_GETTEXT, sent|defwinproc|optional },
95 { WM_ACTIVATE, sent|wparam, 1 },
96 { HCBT_SETFOCUS, hook },
97 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
98 { WM_IME_NOTIFY, sent|defwinproc|optional },
99 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
100 { WM_NCPAINT, sent|wparam|optional, 1 },
101 { WM_GETTEXT, sent|defwinproc|optional },
102 { WM_ERASEBKGND, sent|optional },
103 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
104 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
105 { WM_NCPAINT, sent|wparam|optional, 1 },
106 { WM_ERASEBKGND, sent|optional },
107 { 0 }
109 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
110 * for a visible overlapped window.
112 static const struct message WmSWP_HideOverlappedSeq[] = {
113 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
114 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
115 { 0 }
117 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
118 static const struct message WmShowOverlappedSeq[] = {
119 { WM_SHOWWINDOW, sent|wparam, 1 },
120 { WM_NCPAINT, sent|wparam|optional, 1 },
121 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
122 { WM_NCPAINT, sent|wparam|optional, 1 },
123 { WM_GETTEXT, sent|defwinproc|optional },
124 { WM_ERASEBKGND, sent|optional },
125 { HCBT_ACTIVATE, hook },
126 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
127 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
128 { WM_ACTIVATEAPP, sent|wparam, 1 },
129 { WM_NCACTIVATE, sent|wparam, 1 },
130 { WM_GETTEXT, sent|defwinproc|optional },
131 { WM_ACTIVATE, sent|wparam, 1 },
132 { HCBT_SETFOCUS, hook },
133 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
134 { WM_IME_NOTIFY, sent|defwinproc|optional },
135 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
136 { WM_NCPAINT, sent|wparam|optional, 1 },
137 { WM_GETTEXT, sent|defwinproc|optional },
138 { WM_ERASEBKGND, sent|optional },
139 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
140 { WM_NCCALCSIZE, sent|optional },
141 { WM_NCPAINT, sent|optional },
142 { WM_ERASEBKGND, sent|optional },
143 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
144 * messages. Does that mean that CreateWindow doesn't set initial
145 * window dimensions for overlapped windows?
147 { WM_SIZE, sent },
148 { WM_MOVE, sent },
149 #endif
150 { 0 }
152 /* ShowWindow(SW_HIDE) for a visible overlapped window */
153 static const struct message WmHideOverlappedSeq[] = {
154 { WM_SHOWWINDOW, sent|wparam, 0 },
155 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
156 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
157 { WM_SIZE, sent },
158 { WM_MOVE, sent },
159 { WM_NCACTIVATE, sent|wparam, 0 },
160 { WM_ACTIVATE, sent|wparam, 0 },
161 { WM_ACTIVATEAPP, sent|wparam, 0 },
162 { WM_KILLFOCUS, sent|wparam, 0 },
163 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
164 { WM_IME_NOTIFY, sent|optional|defwinproc },
165 { 0 }
167 /* ShowWindow(SW_HIDE) for an invisible overlapped window */
168 static const struct message WmHideInvisibleOverlappedSeq[] = {
169 { 0 }
171 /* DestroyWindow for a visible overlapped window */
172 static const struct message WmDestroyOverlappedSeq[] = {
173 { HCBT_DESTROYWND, hook },
174 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
175 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
176 { WM_NCACTIVATE, sent|wparam, 0 },
177 { WM_ACTIVATE, sent|wparam, 0 },
178 { WM_ACTIVATEAPP, sent|wparam, 0 },
179 { WM_KILLFOCUS, sent|wparam, 0 },
180 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
181 { WM_IME_NOTIFY, sent|optional|defwinproc },
182 { WM_DESTROY, sent },
183 { WM_NCDESTROY, sent },
184 { 0 }
186 /* CreateWindow (for a child popup window, not initially visible) */
187 static const struct message WmCreateChildPopupSeq[] = {
188 { HCBT_CREATEWND, hook },
189 { WM_NCCREATE, sent },
190 { WM_NCCALCSIZE, sent|wparam, 0 },
191 { WM_CREATE, sent },
192 { WM_SIZE, sent },
193 { WM_MOVE, sent },
194 { 0 }
196 /* CreateWindow (for a popup window, not initially visible,
197 * which sets WS_VISIBLE in WM_CREATE handler)
199 static const struct message WmCreateInvisiblePopupSeq[] = {
200 { HCBT_CREATEWND, hook },
201 { WM_NCCREATE, sent },
202 { WM_NCCALCSIZE, sent|wparam, 0 },
203 { WM_CREATE, sent },
204 { WM_STYLECHANGING, sent },
205 { WM_STYLECHANGED, sent },
206 { WM_SIZE, sent },
207 { WM_MOVE, sent },
208 { 0 }
210 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
211 * for a popup window with WS_VISIBLE style set
213 static const struct message WmShowVisiblePopupSeq_2[] = {
214 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
215 { 0 }
217 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
218 * for a popup window with WS_VISIBLE style set
220 static const struct message WmShowVisiblePopupSeq_3[] = {
221 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
222 { HCBT_ACTIVATE, hook },
223 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
224 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
225 { WM_NCACTIVATE, sent|wparam, 1 },
226 { WM_ACTIVATE, sent|wparam, 1 },
227 { HCBT_SETFOCUS, hook },
228 { WM_KILLFOCUS, sent|parent },
229 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
230 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
231 { WM_IME_NOTIFY, sent|defwinproc|optional },
232 { WM_SETFOCUS, sent|defwinproc },
233 { 0 }
235 /* CreateWindow (for child window, not initially visible) */
236 static const struct message WmCreateChildSeq[] = {
237 { HCBT_CREATEWND, hook },
238 { WM_NCCREATE, sent },
239 /* child is inserted into parent's child list after WM_NCCREATE returns */
240 { WM_NCCALCSIZE, sent|wparam, 0 },
241 { WM_CREATE, sent },
242 { WM_SIZE, sent },
243 { WM_MOVE, sent },
244 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
245 { 0 }
247 /* CreateWindow (for maximized child window, not initially visible) */
248 static const struct message WmCreateMaximizedChildSeq[] = {
249 { HCBT_CREATEWND, hook },
250 { WM_NCCREATE, sent },
251 { WM_NCCALCSIZE, sent|wparam, 0 },
252 { WM_CREATE, sent },
253 { WM_SIZE, sent },
254 { WM_MOVE, sent },
255 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
256 { WM_GETMINMAXINFO, sent },
257 { WM_WINDOWPOSCHANGING, sent },
258 { WM_NCCALCSIZE, sent|wparam, 1 },
259 { WM_WINDOWPOSCHANGED, sent },
260 { WM_SIZE, sent|defwinproc },
261 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
262 { 0 }
264 /* CreateWindow (for a child window, initially visible) */
265 static const struct message WmCreateVisibleChildSeq[] = {
266 { HCBT_CREATEWND, hook },
267 { WM_NCCREATE, sent },
268 /* child is inserted into parent's child list after WM_NCCREATE returns */
269 { WM_NCCALCSIZE, sent|wparam, 0 },
270 { WM_CREATE, sent },
271 { WM_SIZE, sent },
272 { WM_MOVE, sent },
273 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
274 { WM_SHOWWINDOW, sent|wparam, 1 },
275 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
276 { WM_ERASEBKGND, sent|parent|optional },
277 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
278 { 0 }
280 /* ShowWindow(SW_SHOW) for a not visible child window */
281 static const struct message WmShowChildSeq[] = {
282 { WM_SHOWWINDOW, sent|wparam, 1 },
283 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
284 { WM_ERASEBKGND, sent|parent|optional },
285 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
286 { 0 }
288 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
289 * for a not visible child window
291 static const struct message WmShowChildSeq_2[] = {
292 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
293 { WM_CHILDACTIVATE, sent },
294 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
295 { 0 }
297 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
298 * for a not visible child window
300 static const struct message WmShowChildSeq_3[] = {
301 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
302 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
303 { 0 }
305 /* ShowWindow(SW_SHOW) for child with invisible parent */
306 static const struct message WmShowChildInvisibleParentSeq[] = {
307 { WM_SHOWWINDOW, sent|wparam, 1 },
308 { 0 }
310 /* ShowWindow(SW_HIDE) for child with invisible parent */
311 static const struct message WmHideChildInvisibleParentSeq[] = {
312 { WM_SHOWWINDOW, sent|wparam, 0 },
313 { 0 }
315 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
316 static const struct message WmShowChildInvisibleParentSeq_2[] = {
317 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
318 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
319 { 0 }
321 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
322 static const struct message WmHideChildInvisibleParentSeq_2[] = {
323 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
324 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
325 { 0 }
327 /* DestroyWindow for a visible child window */
328 static const struct message WmDestroyChildSeq[] = {
329 { HCBT_DESTROYWND, hook },
330 { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
331 { WM_SHOWWINDOW, sent|wparam, 0 },
332 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
333 { WM_ERASEBKGND, sent|parent|optional },
334 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
335 { HCBT_SETFOCUS, hook }, /* set focus to a parent */
336 { WM_KILLFOCUS, sent },
337 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
338 { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
339 { WM_SETFOCUS, sent|parent },
340 { WM_DESTROY, sent },
341 { WM_DESTROY, sent|optional }, /* a bug in win2k sp4 ? */
342 { WM_NCDESTROY, sent },
343 { WM_NCDESTROY, sent|optional }, /* a bug in win2k sp4 ? */
344 { 0 }
346 /* Moving the mouse in nonclient area */
347 static const struct message WmMouseMoveInNonClientAreaSeq[] = { /* FIXME: add */
348 { WM_NCHITTEST, sent },
349 { WM_SETCURSOR, sent },
350 { WM_NCMOUSEMOVE, posted },
351 { 0 }
353 /* Moving the mouse in client area */
354 static const struct message WmMouseMoveInClientAreaSeq[] = { /* FIXME: add */
355 { WM_NCHITTEST, sent },
356 { WM_SETCURSOR, sent },
357 { WM_MOUSEMOVE, posted },
358 { 0 }
360 /* Moving by dragging the title bar (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
361 static const struct message WmDragTitleBarSeq[] = { /* FIXME: add */
362 { WM_NCLBUTTONDOWN, sent|wparam, HTCAPTION },
363 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_MOVE+2 },
364 { WM_GETMINMAXINFO, sent|defwinproc },
365 { WM_ENTERSIZEMOVE, sent|defwinproc },
366 { WM_WINDOWPOSCHANGING, sent|defwinproc },
367 { WM_WINDOWPOSCHANGED, sent|defwinproc },
368 { WM_MOVE, sent|defwinproc },
369 { WM_EXITSIZEMOVE, sent|defwinproc },
370 { 0 }
372 /* Sizing by dragging the thick borders (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
373 static const struct message WmDragThickBordersBarSeq[] = { /* FIXME: add */
374 { WM_NCLBUTTONDOWN, sent|wparam, 0xd },
375 { WM_SYSCOMMAND, sent|defwinproc|wparam, 0xf004 },
376 { WM_GETMINMAXINFO, sent|defwinproc },
377 { WM_ENTERSIZEMOVE, sent|defwinproc },
378 { WM_SIZING, sent|defwinproc|wparam, 4}, /* one for each mouse movement */
379 { WM_WINDOWPOSCHANGING, sent|defwinproc },
380 { WM_GETMINMAXINFO, sent|defwinproc },
381 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
382 { WM_NCPAINT, sent|defwinproc|wparam, 1 },
383 { WM_GETTEXT, sent|defwinproc },
384 { WM_ERASEBKGND, sent|defwinproc },
385 { WM_WINDOWPOSCHANGED, sent|defwinproc },
386 { WM_MOVE, sent|defwinproc },
387 { WM_SIZE, sent|defwinproc },
388 { WM_EXITSIZEMOVE, sent|defwinproc },
389 { 0 }
391 /* Resizing child window with MoveWindow (32) */
392 static const struct message WmResizingChildWithMoveWindowSeq[] = {
393 { WM_WINDOWPOSCHANGING, sent },
394 { WM_NCCALCSIZE, sent|wparam, 1 },
395 { WM_ERASEBKGND, sent|optional },
396 { WM_WINDOWPOSCHANGED, sent },
397 { WM_MOVE, sent|defwinproc },
398 { WM_SIZE, sent|defwinproc },
399 { 0 }
401 /* Clicking on inactive button */
402 static const struct message WmClickInactiveButtonSeq[] = { /* FIXME: add */
403 { WM_NCHITTEST, sent },
404 { WM_PARENTNOTIFY, sent|parent|wparam, WM_LBUTTONDOWN },
405 { WM_MOUSEACTIVATE, sent },
406 { WM_MOUSEACTIVATE, sent|parent|defwinproc },
407 { WM_SETCURSOR, sent },
408 { WM_SETCURSOR, sent|parent|defwinproc },
409 { WM_LBUTTONDOWN, posted },
410 { WM_KILLFOCUS, posted|parent },
411 { WM_SETFOCUS, posted },
412 { WM_CTLCOLORBTN, posted|parent },
413 { BM_SETSTATE, posted },
414 { WM_CTLCOLORBTN, posted|parent },
415 { WM_LBUTTONUP, posted },
416 { BM_SETSTATE, posted },
417 { WM_CTLCOLORBTN, posted|parent },
418 { WM_COMMAND, posted|parent },
419 { 0 }
421 /* Reparenting a button (16/32) */
422 /* The last child (button) reparented gets topmost for its new parent. */
423 static const struct message WmReparentButtonSeq[] = { /* FIXME: add */
424 { WM_SHOWWINDOW, sent|wparam, 0 },
425 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER },
426 { WM_ERASEBKGND, sent|parent },
427 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER },
428 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOZORDER },
429 { WM_CHILDACTIVATE, sent },
430 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW|SWP_NOZORDER },
431 { WM_MOVE, sent|defwinproc },
432 { WM_SHOWWINDOW, sent|wparam, 1 },
433 { 0 }
435 /* Creation of a custom dialog (32) */
436 static const struct message WmCreateCustomDialogSeq[] = {
437 { HCBT_CREATEWND, hook },
438 { WM_GETMINMAXINFO, sent },
439 { WM_NCCREATE, sent },
440 { WM_NCCALCSIZE, sent|wparam, 0 },
441 { WM_CREATE, sent },
442 { WM_SHOWWINDOW, sent|wparam, 1 },
443 { HCBT_ACTIVATE, hook },
444 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
445 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
446 { WM_NCACTIVATE, sent|wparam, 1 },
447 { WM_GETTEXT, sent|optional|defwinproc },
448 { WM_GETICON, sent|optional|defwinproc },
449 { WM_GETICON, sent|optional|defwinproc },
450 { WM_GETICON, sent|optional|defwinproc },
451 { WM_GETTEXT, sent|optional|defwinproc },
452 { WM_ACTIVATE, sent|wparam, 1 },
453 { WM_KILLFOCUS, sent|parent },
454 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
455 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
456 { WM_IME_NOTIFY, sent|optional|defwinproc },
457 { WM_SETFOCUS, sent },
458 { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
459 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
460 { WM_NCPAINT, sent|wparam, 1 },
461 { WM_GETTEXT, sent|optional|defwinproc },
462 { WM_GETICON, sent|optional|defwinproc },
463 { WM_GETICON, sent|optional|defwinproc },
464 { WM_GETICON, sent|optional|defwinproc },
465 { WM_GETTEXT, sent|optional|defwinproc },
466 { WM_ERASEBKGND, sent },
467 { WM_CTLCOLORDLG, sent|defwinproc },
468 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
469 { WM_GETTEXT, sent|optional },
470 { WM_GETICON, sent|optional },
471 { WM_GETICON, sent|optional },
472 { WM_GETICON, sent|optional },
473 { WM_GETTEXT, sent|optional },
474 { WM_NCCALCSIZE, sent|optional },
475 { WM_NCPAINT, sent|optional },
476 { WM_GETTEXT, sent|optional|defwinproc },
477 { WM_GETICON, sent|optional|defwinproc },
478 { WM_GETICON, sent|optional|defwinproc },
479 { WM_GETICON, sent|optional|defwinproc },
480 { WM_GETTEXT, sent|optional|defwinproc },
481 { WM_ERASEBKGND, sent|optional },
482 { WM_CTLCOLORDLG, sent|optional|defwinproc },
483 { WM_SIZE, sent },
484 { WM_MOVE, sent },
485 { 0 }
487 /* Calling EndDialog for a custom dialog (32) */
488 static const struct message WmEndCustomDialogSeq[] = {
489 { WM_WINDOWPOSCHANGING, sent },
490 { WM_WINDOWPOSCHANGED, sent },
491 { WM_GETTEXT, sent|optional },
492 { WM_GETICON, sent|optional },
493 { WM_GETICON, sent|optional },
494 { WM_GETICON, sent|optional },
495 { HCBT_ACTIVATE, hook },
496 { WM_NCACTIVATE, sent|wparam, 0 },
497 { WM_GETTEXT, sent|optional|defwinproc },
498 { WM_GETICON, sent|optional|defwinproc },
499 { WM_GETICON, sent|optional|defwinproc },
500 { WM_GETICON, sent|optional|defwinproc },
501 { WM_GETTEXT, sent|optional|defwinproc },
502 { WM_ACTIVATE, sent|wparam, 0 },
503 { WM_WINDOWPOSCHANGING, sent|optional },
504 { HCBT_SETFOCUS, hook },
505 { WM_KILLFOCUS, sent },
506 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
507 { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
508 { WM_IME_NOTIFY, sent|optional },
509 { WM_SETFOCUS, sent|parent|defwinproc },
510 { 0 }
512 /* Creation and destruction of a modal dialog (32) */
513 static const struct message WmModalDialogSeq[] = {
514 { WM_CANCELMODE, sent|parent },
515 { HCBT_SETFOCUS, hook },
516 { WM_KILLFOCUS, sent|parent },
517 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
518 { WM_ENABLE, sent|parent|wparam, 0 },
519 { HCBT_CREATEWND, hook },
520 { WM_SETFONT, sent },
521 { WM_INITDIALOG, sent },
522 { WM_CHANGEUISTATE, sent|optional },
523 { WM_SHOWWINDOW, sent },
524 { HCBT_ACTIVATE, hook },
525 { WM_WINDOWPOSCHANGING, sent },
526 { WM_NCACTIVATE, sent|wparam, 1 },
527 { WM_GETICON, sent|optional },
528 { WM_GETICON, sent|optional },
529 { WM_GETICON, sent|optional },
530 { WM_GETTEXT, sent|optional },
531 { WM_ACTIVATE, sent|wparam, 1 },
532 { WM_WINDOWPOSCHANGING, sent },
533 { WM_NCPAINT, sent },
534 { WM_GETICON, sent|optional },
535 { WM_GETICON, sent|optional },
536 { WM_GETICON, sent|optional },
537 { WM_GETTEXT, sent|optional },
538 { WM_ERASEBKGND, sent },
539 { WM_CTLCOLORDLG, sent },
540 { WM_WINDOWPOSCHANGED, sent },
541 { WM_GETICON, sent|optional },
542 { WM_GETICON, sent|optional },
543 { WM_GETICON, sent|optional },
544 { WM_GETTEXT, sent|optional },
545 { WM_NCCALCSIZE, sent|optional },
546 { WM_NCPAINT, sent|optional },
547 { WM_GETICON, sent|optional },
548 { WM_GETICON, sent|optional },
549 { WM_GETICON, sent|optional },
550 { WM_GETTEXT, sent|optional },
551 { WM_ERASEBKGND, sent|optional },
552 { WM_CTLCOLORDLG, sent|optional },
553 { WM_PAINT, sent|optional },
554 { WM_CTLCOLORBTN, sent },
555 { WM_ENTERIDLE, sent|parent|optional },
556 { WM_TIMER, sent },
557 { WM_ENABLE, sent|parent|wparam, 1 },
558 { WM_WINDOWPOSCHANGING, sent },
559 { WM_WINDOWPOSCHANGED, sent },
560 { WM_GETICON, sent|optional },
561 { WM_GETICON, sent|optional },
562 { WM_GETICON, sent|optional },
563 { WM_GETTEXT, sent|optional },
564 { HCBT_ACTIVATE, hook },
565 { WM_NCACTIVATE, sent|wparam, 0 },
566 { WM_GETICON, sent|optional },
567 { WM_GETICON, sent|optional },
568 { WM_GETICON, sent|optional },
569 { WM_GETTEXT, sent|optional },
570 { WM_ACTIVATE, sent|wparam, 0 },
571 { WM_WINDOWPOSCHANGING, sent|optional },
572 { HCBT_SETFOCUS, hook },
573 { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
574 { WM_SETFOCUS, sent|parent|defwinproc },
575 { HCBT_DESTROYWND, hook },
576 { WM_DESTROY, sent },
577 { WM_NCDESTROY, sent },
578 { 0 }
580 /* Creation of a modal dialog that is resized inside WM_INITDIALOG (32) */
581 static const struct message WmCreateModalDialogResizeSeq[] = { /* FIXME: add */
582 /* (inside dialog proc, handling WM_INITDIALOG) */
583 { WM_WINDOWPOSCHANGING, sent },
584 { WM_NCCALCSIZE, sent },
585 { WM_NCACTIVATE, sent|parent|wparam, 0 },
586 { WM_GETTEXT, sent|defwinproc },
587 { WM_ACTIVATE, sent|parent|wparam, 0 },
588 { WM_WINDOWPOSCHANGING, sent },
589 { WM_WINDOWPOSCHANGING, sent|parent },
590 { WM_NCACTIVATE, sent|wparam, 1 },
591 { WM_ACTIVATE, sent|wparam, 1 },
592 { WM_WINDOWPOSCHANGED, sent },
593 { WM_SIZE, sent|defwinproc },
594 /* (setting focus) */
595 { WM_SHOWWINDOW, sent|wparam, 1 },
596 { WM_WINDOWPOSCHANGING, sent },
597 { WM_NCPAINT, sent },
598 { WM_GETTEXT, sent|defwinproc },
599 { WM_ERASEBKGND, sent },
600 { WM_CTLCOLORDLG, sent|defwinproc },
601 { WM_WINDOWPOSCHANGED, sent },
602 { WM_PAINT, sent },
603 /* (bunch of WM_CTLCOLOR* for each control) */
604 { WM_PAINT, sent|parent },
605 { WM_ENTERIDLE, sent|parent|wparam, 0 },
606 { WM_SETCURSOR, sent|parent },
607 { 0 }
609 /* SetMenu for NonVisible windows with size change*/
610 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
611 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
612 { WM_NCCALCSIZE, sent|wparam, 1 },
613 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
614 { WM_MOVE, sent|defwinproc },
615 { WM_SIZE, sent|defwinproc },
616 { WM_GETICON, sent|optional },
617 { WM_GETICON, sent|optional },
618 { WM_GETICON, sent|optional },
619 { WM_GETTEXT, sent|optional },
620 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
621 { 0 }
623 /* SetMenu for NonVisible windows with no size change */
624 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
625 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
626 { WM_NCCALCSIZE, sent|wparam, 1 },
627 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
628 { 0 }
630 /* SetMenu for Visible windows with size change */
631 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
632 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
633 { WM_NCCALCSIZE, sent|wparam, 1 },
634 { WM_NCPAINT, sent|wparam, 1 },
635 { WM_GETTEXT, sent|defwinproc|optional },
636 { WM_ERASEBKGND, sent|optional },
637 { WM_ACTIVATE, sent|optional },
638 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
639 { WM_MOVE, sent|defwinproc },
640 { WM_SIZE, sent|defwinproc },
641 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
642 { WM_NCPAINT, sent|wparam|optional, 1 },
643 { WM_ERASEBKGND, sent|optional },
644 { 0 }
646 /* SetMenu for Visible windows with no size change */
647 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
648 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
649 { WM_NCCALCSIZE, sent|wparam, 1 },
650 { WM_NCPAINT, sent|wparam, 1 },
651 { WM_GETTEXT, sent|defwinproc|optional },
652 { WM_ERASEBKGND, sent|optional },
653 { WM_ACTIVATE, sent|optional },
654 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
655 { 0 }
657 /* DrawMenuBar for a visible window */
658 static const struct message WmDrawMenuBarSeq[] =
660 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
661 { WM_NCCALCSIZE, sent|wparam, 1 },
662 { WM_NCPAINT, sent|wparam, 1 },
663 { WM_GETTEXT, sent|defwinproc|optional },
664 { WM_ERASEBKGND, sent|optional },
665 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
666 { 0 }
669 static const struct message WmSetRedrawFalseSeq[] =
671 { WM_SETREDRAW, sent|wparam, 0 },
672 { 0 }
675 static const struct message WmSetRedrawTrueSeq[] =
677 { WM_SETREDRAW, sent|wparam, 1 },
678 { 0 }
681 static const struct message WmEnableWindowSeq[] =
683 { WM_CANCELMODE, sent },
684 { WM_ENABLE, sent },
685 { 0 }
688 static const struct message WmGetScrollRangeSeq[] =
690 { SBM_GETRANGE, sent },
691 { 0 }
693 static const struct message WmGetScrollInfoSeq[] =
695 { SBM_GETSCROLLINFO, sent },
696 { 0 }
698 static const struct message WmSetScrollRangeSeq[] =
700 /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
701 sends SBM_SETSCROLLINFO.
703 { SBM_SETSCROLLINFO, sent },
704 { 0 }
706 /* SetScrollRange for a window without a non-client area */
707 static const struct message WmSetScrollRangeHVSeq[] =
709 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
710 { WM_NCCALCSIZE, sent|wparam, 1 },
711 { WM_GETTEXT, sent|defwinproc|optional },
712 { WM_ERASEBKGND, sent|optional },
713 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
714 { 0 }
716 /* SetScrollRange for a window with a non-client area */
717 static const struct message WmSetScrollRangeHV_NC_Seq[] =
719 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
720 { WM_NCCALCSIZE, sent|wparam, 1 },
721 { WM_NCPAINT, sent|optional },
722 { WM_GETTEXT, sent|defwinproc|optional },
723 { WM_GETICON, sent|optional|defwinproc },
724 { WM_GETICON, sent|optional|defwinproc },
725 { WM_GETICON, sent|optional|defwinproc },
726 { WM_GETTEXT, sent|defwinproc|optional },
727 { WM_ERASEBKGND, sent|optional },
728 { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
729 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
730 { WM_SIZE, sent|defwinproc },
731 { WM_GETTEXT, sent|optional },
732 { WM_GETICON, sent|optional },
733 { WM_GETICON, sent|optional },
734 { WM_GETICON, sent|optional },
735 { WM_GETTEXT, sent|optional },
736 { WM_GETICON, sent|optional },
737 { WM_GETICON, sent|optional },
738 { WM_GETICON, sent|optional },
739 { WM_GETTEXT, sent|optional },
740 { WM_GETICON, sent|optional },
741 { WM_GETICON, sent|optional },
742 { WM_GETICON, sent|optional },
743 { WM_GETTEXT, sent|optional },
744 { 0 }
747 static int after_end_dialog;
748 static int sequence_cnt, sequence_size;
749 static struct message* sequence;
751 static void add_message(const struct message *msg)
753 if (!sequence)
755 sequence_size = 10;
756 sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof (struct message) );
758 if (sequence_cnt == sequence_size)
760 sequence_size *= 2;
761 sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof (struct message) );
763 assert(sequence);
765 sequence[sequence_cnt].message = msg->message;
766 sequence[sequence_cnt].flags = msg->flags;
767 sequence[sequence_cnt].wParam = msg->wParam;
768 sequence[sequence_cnt].lParam = msg->lParam;
770 sequence_cnt++;
773 static void flush_sequence()
775 HeapFree(GetProcessHeap(), 0, sequence);
776 sequence = 0;
777 sequence_cnt = sequence_size = 0;
780 static void ok_sequence(const struct message *expected, const char *context, int todo)
782 static const struct message end_of_sequence = { 0, 0, 0, 0 };
783 const struct message *actual;
785 add_message(&end_of_sequence);
787 actual = sequence;
789 while (expected->message && actual->message)
791 trace("expected %04x - actual %04x\n", expected->message, actual->message);
793 if (expected->message == actual->message)
795 if (expected->flags & wparam)
796 ok (expected->wParam == actual->wParam,
797 "%s: in msg 0x%04x expecting wParam 0x%x got 0x%x\n",
798 context, expected->message, expected->wParam, actual->wParam);
799 if (expected->flags & lparam)
800 ok (expected->lParam == actual->lParam,
801 "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
802 context, expected->message, expected->lParam, actual->lParam);
803 ok ((expected->flags & defwinproc) == (actual->flags & defwinproc),
804 "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
805 context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
806 ok ((expected->flags & beginpaint) == (actual->flags & beginpaint),
807 "%s: the msg 0x%04x should %shave been sent by BeginPaint\n",
808 context, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
809 ok ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
810 "%s: the msg 0x%04x should have been %s\n",
811 context, expected->message, (expected->flags & posted) ? "posted" : "sent");
812 ok ((expected->flags & parent) == (actual->flags & parent),
813 "%s: the msg 0x%04x was expected in %s\n",
814 context, expected->message, (expected->flags & parent) ? "parent" : "child");
815 ok ((expected->flags & hook) == (actual->flags & hook),
816 "%s: the msg 0x%04x should have been sent by a hook\n",
817 context, expected->message);
818 expected++;
819 actual++;
821 else if (expected->flags & optional)
822 expected++;
823 else if (todo)
825 todo_wine {
826 ok (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
827 context, expected->message, actual->message);
828 expected++;
829 actual++;
832 else
834 ok (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
835 context, expected->message, actual->message);
836 expected++;
837 actual++;
841 /* skip all optional trailing messages */
842 while (expected->message && (expected->flags & optional))
843 expected++;
845 if (todo)
847 todo_wine {
848 if (expected->message || actual->message)
849 ok (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
850 context, expected->message, actual->message);
853 else
855 if (expected->message || actual->message)
856 ok (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
857 context, expected->message, actual->message);
860 flush_sequence();
863 /******************************** MDI test **********************************/
865 /* CreateWindow for MDI frame window, initially visible */
866 static const struct message WmCreateMDIframeSeq[] = {
867 { HCBT_CREATEWND, hook },
868 { WM_GETMINMAXINFO, sent },
869 { WM_NCCREATE, sent },
870 { WM_NCCALCSIZE, sent|wparam, 0 },
871 { WM_CREATE, sent },
872 { WM_SHOWWINDOW, sent|wparam, 1 },
873 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
874 { HCBT_ACTIVATE, hook },
875 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
876 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
877 { WM_WINDOWPOSCHANGED, sent|wparam|optional, 0 }, /* Win9x */
878 { WM_ACTIVATEAPP, sent|wparam, 1 },
879 { WM_NCACTIVATE, sent|wparam, 1 },
880 { WM_ACTIVATE, sent|wparam, 1 },
881 { HCBT_SETFOCUS, hook },
882 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
883 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
884 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
885 { WM_SIZE, sent },
886 { WM_MOVE, sent },
887 { 0 }
889 /* DestroyWindow for MDI frame window, initially visible */
890 static const struct message WmDestroyMDIframeSeq[] = {
891 { HCBT_DESTROYWND, hook },
892 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
893 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
894 { WM_NCACTIVATE, sent|wparam, 0 },
895 { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
896 { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
897 { WM_DESTROY, sent },
898 { WM_NCDESTROY, sent },
899 { 0 }
901 /* CreateWindow for MDI client window, initially visible */
902 static const struct message WmCreateMDIclientSeq[] = {
903 { HCBT_CREATEWND, hook },
904 { WM_NCCREATE, sent },
905 { WM_NCCALCSIZE, sent|wparam, 0 },
906 { WM_CREATE, sent },
907 { WM_SIZE, sent },
908 { WM_MOVE, sent },
909 { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
910 { WM_SHOWWINDOW, sent|wparam, 1 },
911 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
912 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
913 { 0 }
915 /* DestroyWindow for MDI client window, initially visible */
916 static const struct message WmDestroyMDIclientSeq[] = {
917 { HCBT_DESTROYWND, hook },
918 { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
919 { WM_SHOWWINDOW, sent|wparam, 0 },
920 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
921 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
922 { WM_DESTROY, sent },
923 { WM_NCDESTROY, sent },
924 { 0 }
926 /* CreateWindow for MDI child window, initially visible */
927 static const struct message WmCreateMDIchildVisibleSeq[] = {
928 { HCBT_CREATEWND, hook },
929 { WM_NCCREATE, sent },
930 { WM_NCCALCSIZE, sent|wparam, 0 },
931 { WM_CREATE, sent },
932 { WM_SIZE, sent },
933 { WM_MOVE, sent },
934 /* Win2k sends wparam set to
935 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
936 * while Win9x doesn't bother to set child window id according to
937 * CLIENTCREATESTRUCT.idFirstChild
939 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
940 { WM_SHOWWINDOW, sent|wparam, 1 },
941 { WM_WINDOWPOSCHANGING, sent|wparam, 0 }, /*SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER*/
942 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
943 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
944 { WM_WINDOWPOSCHANGING, sent|wparam, 0 }, /*SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE*/
945 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
946 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 }, /*SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/
948 /* Win9x: message sequence terminates here. */
950 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
951 { HCBT_SETFOCUS, hook }, /* in MDI client */
952 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
953 { WM_SETFOCUS, sent }, /* in MDI client */
954 { HCBT_SETFOCUS, hook },
955 { WM_KILLFOCUS, sent }, /* in MDI client */
956 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
957 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
958 { WM_SETFOCUS, sent|defwinproc },
959 { WM_MDIACTIVATE, sent|defwinproc },
960 { 0 }
962 /* DestroyWindow for MDI child window, initially visible */
963 static const struct message WmDestroyMDIchildVisibleSeq[] = {
964 { HCBT_DESTROYWND, hook },
965 /* Win2k sends wparam set to
966 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
967 * while Win9x doesn't bother to set child window id according to
968 * CLIENTCREATESTRUCT.idFirstChild
970 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
971 { WM_SHOWWINDOW, sent|wparam, 0 },
972 { WM_WINDOWPOSCHANGING, sent|wparam, 0 }, /*SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER*/
973 { WM_ERASEBKGND, sent|parent|optional },
974 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
976 /* { WM_DESTROY, sent }
977 * Win9x: message sequence terminates here.
980 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
981 { WM_KILLFOCUS, sent },
982 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
983 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
984 { WM_SETFOCUS, sent }, /* in MDI client */
986 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
987 { WM_KILLFOCUS, sent }, /* in MDI client */
988 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
989 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
990 { WM_SETFOCUS, sent }, /* in MDI client */
992 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
993 { WM_KILLFOCUS, sent },
994 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
995 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
996 { WM_SETFOCUS, sent }, /* in MDI client */
998 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
999 { WM_KILLFOCUS, sent }, /* in MDI client */
1000 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1001 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1002 { WM_SETFOCUS, sent }, /* in MDI client */
1004 { WM_DESTROY, sent },
1006 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1007 { WM_KILLFOCUS, sent },
1008 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1009 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1010 { WM_SETFOCUS, sent }, /* in MDI client */
1012 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1013 { WM_KILLFOCUS, sent }, /* in MDI client */
1014 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1015 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1016 { WM_SETFOCUS, sent }, /* in MDI client */
1018 { WM_NCDESTROY, sent },
1019 { 0 }
1021 /* CreateWindow for MDI child window, initially invisible */
1022 static const struct message WmCreateMDIchildInvisibleSeq[] = {
1023 { HCBT_CREATEWND, hook },
1024 { WM_NCCREATE, sent },
1025 { WM_NCCALCSIZE, sent|wparam, 0 },
1026 { WM_CREATE, sent },
1027 { WM_SIZE, sent },
1028 { WM_MOVE, sent },
1029 /* Win2k sends wparam set to
1030 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1031 * while Win9x doesn't bother to set child window id according to
1032 * CLIENTCREATESTRUCT.idFirstChild
1034 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1035 { 0 }
1037 /* DestroyWindow for MDI child window, initially invisible */
1038 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
1039 { HCBT_DESTROYWND, hook },
1040 /* Win2k sends wparam set to
1041 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1042 * while Win9x doesn't bother to set child window id according to
1043 * CLIENTCREATESTRUCT.idFirstChild
1045 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1046 { WM_DESTROY, sent },
1047 { WM_NCDESTROY, sent },
1048 { 0 }
1051 static HWND mdi_client;
1052 static WNDPROC old_mdi_client_proc;
1054 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1056 struct message msg;
1058 /* do not log painting messages */
1059 if (message != WM_PAINT &&
1060 message != WM_ERASEBKGND &&
1061 message != WM_NCPAINT &&
1062 message != WM_GETTEXT)
1064 trace("mdi client: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1066 msg.message = message;
1067 msg.flags = sent|wparam|lparam;
1068 msg.wParam = wParam;
1069 msg.lParam = lParam;
1070 add_message(&msg);
1073 return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
1076 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1078 static long defwndproc_counter = 0;
1079 LRESULT ret;
1080 struct message msg;
1082 /* do not log painting messages */
1083 if (message != WM_PAINT &&
1084 message != WM_ERASEBKGND &&
1085 message != WM_NCPAINT &&
1086 message != WM_GETTEXT)
1088 trace("mdi child: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1090 switch (message)
1092 case WM_WINDOWPOSCHANGING:
1093 case WM_WINDOWPOSCHANGED:
1095 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
1097 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
1098 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
1099 winpos->hwnd, winpos->hwndInsertAfter,
1100 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
1101 break;
1105 msg.message = message;
1106 msg.flags = sent|wparam|lparam;
1107 if (defwndproc_counter) msg.flags |= defwinproc;
1108 msg.wParam = wParam;
1109 msg.lParam = lParam;
1110 add_message(&msg);
1113 defwndproc_counter++;
1114 ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
1115 defwndproc_counter--;
1117 return ret;
1120 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1122 static long defwndproc_counter = 0;
1123 LRESULT ret;
1124 struct message msg;
1126 /* do not log painting messages */
1127 if (message != WM_PAINT &&
1128 message != WM_ERASEBKGND &&
1129 message != WM_NCPAINT &&
1130 message != WM_GETTEXT)
1132 trace("mdi frame: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1134 msg.message = message;
1135 msg.flags = sent|wparam|lparam;
1136 if (defwndproc_counter) msg.flags |= defwinproc;
1137 msg.wParam = wParam;
1138 msg.lParam = lParam;
1139 add_message(&msg);
1142 defwndproc_counter++;
1143 ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
1144 defwndproc_counter--;
1146 return ret;
1149 static BOOL mdi_RegisterWindowClasses(void)
1151 WNDCLASSA cls;
1153 cls.style = 0;
1154 cls.lpfnWndProc = mdi_frame_wnd_proc;
1155 cls.cbClsExtra = 0;
1156 cls.cbWndExtra = 0;
1157 cls.hInstance = GetModuleHandleA(0);
1158 cls.hIcon = 0;
1159 cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
1160 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
1161 cls.lpszMenuName = NULL;
1162 cls.lpszClassName = "MDI_frame_class";
1163 if (!RegisterClassA(&cls)) return FALSE;
1165 cls.lpfnWndProc = mdi_child_wnd_proc;
1166 cls.lpszClassName = "MDI_child_class";
1167 if (!RegisterClassA(&cls)) return FALSE;
1169 if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
1170 old_mdi_client_proc = cls.lpfnWndProc;
1171 cls.hInstance = GetModuleHandleA(0);
1172 cls.lpfnWndProc = mdi_client_hook_proc;
1173 cls.lpszClassName = "MDI_client_class";
1174 if (!RegisterClassA(&cls)) assert(0);
1176 return TRUE;
1179 static void test_mdi_messages(void)
1181 CLIENTCREATESTRUCT client_cs;
1182 HWND mdi_frame, mdi_child;
1184 assert(mdi_RegisterWindowClasses());
1186 flush_sequence();
1188 trace("creating MDI frame window\n");
1189 mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
1190 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
1191 WS_MAXIMIZEBOX | WS_VISIBLE,
1192 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
1193 GetDesktopWindow(), 0,
1194 GetModuleHandleA(0), NULL);
1195 assert(mdi_frame);
1196 ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", TRUE);
1198 trace("creating MDI client window\n");
1199 client_cs.hWindowMenu = 0;
1200 client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
1201 mdi_client = CreateWindowExA(0, "MDI_client_class",
1202 NULL,
1203 WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
1204 0, 0, 0, 0,
1205 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
1206 assert(mdi_client);
1207 ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", TRUE);
1209 ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
1211 SetFocus(0);
1212 flush_sequence();
1214 trace("creating visible MDI child window\n");
1215 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
1216 WS_CHILD | WS_VISIBLE,
1217 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
1218 mdi_client, 0, GetModuleHandleA(0), NULL);
1219 assert(mdi_child);
1220 ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", TRUE);
1222 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
1223 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
1225 DestroyWindow(mdi_child);
1226 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
1228 SetFocus(0);
1229 flush_sequence();
1231 trace("creating invisible MDI child window\n");
1232 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
1233 WS_CHILD,
1234 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
1235 mdi_client, 0, GetModuleHandleA(0), NULL);
1236 assert(mdi_child);
1237 ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", TRUE);
1239 ok(!(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
1240 ok(!IsWindowVisible(mdi_child), "MDI child should not be visible\n");
1242 DestroyWindow(mdi_child);
1243 ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", TRUE);
1245 DestroyWindow(mdi_client);
1246 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
1248 DestroyWindow(mdi_frame);
1249 ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
1251 /************************* End of MDI test **********************************/
1253 static void test_WM_SETREDRAW(HWND hwnd)
1255 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
1257 flush_sequence();
1259 SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
1260 ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
1262 ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
1263 ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
1265 flush_sequence();
1266 SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
1267 ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
1269 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
1270 ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
1272 /* restore original WS_VISIBLE state */
1273 SetWindowLongA(hwnd, GWL_STYLE, style);
1275 flush_sequence();
1278 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1280 struct message msg;
1282 trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1284 msg.message = message;
1285 msg.flags = sent|wparam|lparam;
1286 msg.wParam = wParam;
1287 msg.lParam = lParam;
1288 add_message(&msg);
1290 if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
1291 if (message == WM_TIMER) EndDialog( hwnd, 0 );
1292 return 0;
1295 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
1297 DWORD style, exstyle;
1298 INT xmin, xmax;
1300 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
1301 style = GetWindowLongA(hwnd, GWL_STYLE);
1302 /* do not be confused by WS_DLGFRAME set */
1303 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
1305 if (clear) ok(style & clear, "style %08lx should be set\n", clear);
1306 if (set) ok(!(style & set), "style %08lx should not be set\n", set);
1308 ok(SetScrollRange(hwnd, ctl, min, max, FALSE), "SetScrollRange(%d) error %ld\n", ctl, GetLastError());
1309 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
1310 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
1311 else
1312 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", TRUE);
1314 style = GetWindowLongA(hwnd, GWL_STYLE);
1315 if (set) ok(style & set, "style %08lx should be set\n", set);
1316 if (clear) ok(!(style & clear), "style %08lx should not be set\n", clear);
1318 /* a subsequent call should do nothing */
1319 ok(SetScrollRange(hwnd, ctl, min, max, FALSE), "SetScrollRange(%d) error %ld\n", ctl, GetLastError());
1320 ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
1322 xmin = 0xdeadbeef;
1323 xmax = 0xdeadbeef;
1324 trace("Ignore GetScrollRange error below if you are on Win9x\n");
1325 ok(GetScrollRange(hwnd, ctl, &xmin, &xmax), "GetScrollRange(%d) error %ld\n", ctl, GetLastError());
1326 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT)", FALSE);
1327 ok(xmin == min, "unexpected min scroll value %d\n", xmin);
1328 ok(xmax == max, "unexpected max scroll value %d\n", xmax);
1331 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
1333 DWORD style, exstyle;
1334 SCROLLINFO si;
1336 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
1337 style = GetWindowLongA(hwnd, GWL_STYLE);
1338 /* do not be confused by WS_DLGFRAME set */
1339 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
1341 if (clear) ok(style & clear, "style %08lx should be set\n", clear);
1342 if (set) ok(!(style & set), "style %08lx should not be set\n", set);
1344 si.cbSize = sizeof(si);
1345 si.fMask = SIF_RANGE;
1346 si.nMin = min;
1347 si.nMax = max;
1348 SetScrollInfo(hwnd, ctl, &si, TRUE);
1349 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
1350 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
1351 else
1352 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", TRUE);
1354 style = GetWindowLongA(hwnd, GWL_STYLE);
1355 if (set) ok(style & set, "style %08lx should be set\n", set);
1356 if (clear) ok(!(style & clear), "style %08lx should not be set\n", clear);
1358 /* a subsequent call should do nothing */
1359 SetScrollInfo(hwnd, ctl, &si, TRUE);
1360 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
1362 si.fMask = SIF_PAGE;
1363 si.nPage = 5;
1364 SetScrollInfo(hwnd, ctl, &si, FALSE);
1365 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
1367 si.fMask = SIF_POS;
1368 si.nPos = max - 1;
1369 SetScrollInfo(hwnd, ctl, &si, FALSE);
1370 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
1372 si.fMask = SIF_RANGE;
1373 si.nMin = 0xdeadbeef;
1374 si.nMax = 0xdeadbeef;
1375 ok(GetScrollInfo(hwnd, ctl, &si), "GetScrollInfo error %ld\n", GetLastError());
1376 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT)", FALSE);
1377 ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
1378 ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
1381 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
1382 static void test_scroll_messages(HWND hwnd)
1384 SCROLLINFO si;
1385 INT min, max;
1387 min = 0xdeadbeef;
1388 max = 0xdeadbeef;
1389 ok(GetScrollRange(hwnd, SB_CTL, &min, &max), "GetScrollRange error %ld\n", GetLastError());
1390 if (sequence->message != WmGetScrollRangeSeq[0].message)
1391 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
1392 /* values of min and max are undefined */
1393 flush_sequence();
1395 ok(SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE), "SetScrollRange error %ld\n", GetLastError());
1396 if (sequence->message != WmSetScrollRangeSeq[0].message)
1397 trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
1398 flush_sequence();
1400 min = 0xdeadbeef;
1401 max = 0xdeadbeef;
1402 ok(GetScrollRange(hwnd, SB_CTL, &min, &max), "GetScrollRange error %ld\n", GetLastError());
1403 if (sequence->message != WmGetScrollRangeSeq[0].message)
1404 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
1405 /* values of min and max are undefined */
1406 flush_sequence();
1408 si.cbSize = sizeof(si);
1409 si.fMask = SIF_RANGE;
1410 si.nMin = 20;
1411 si.nMax = 160;
1412 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
1413 if (sequence->message != WmSetScrollRangeSeq[0].message)
1414 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
1415 flush_sequence();
1417 si.fMask = SIF_PAGE;
1418 si.nPage = 10;
1419 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
1420 if (sequence->message != WmSetScrollRangeSeq[0].message)
1421 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
1422 flush_sequence();
1424 si.fMask = SIF_POS;
1425 si.nPos = 20;
1426 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
1427 if (sequence->message != WmSetScrollRangeSeq[0].message)
1428 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
1429 flush_sequence();
1431 si.fMask = SIF_RANGE;
1432 si.nMin = 0xdeadbeef;
1433 si.nMax = 0xdeadbeef;
1434 ok(GetScrollInfo(hwnd, SB_CTL, &si), "GetScrollInfo error %ld\n", GetLastError());
1435 if (sequence->message != WmGetScrollInfoSeq[0].message)
1436 trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
1437 /* values of min and max are undefined */
1438 flush_sequence();
1440 /* set WS_HSCROLL */
1441 test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
1442 /* clear WS_HSCROLL */
1443 test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
1445 /* set WS_HSCROLL */
1446 test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
1447 /* clear WS_HSCROLL */
1448 test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
1450 /* set WS_VSCROLL */
1451 test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
1452 /* clear WS_VSCROLL */
1453 test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
1455 /* set WS_VSCROLL */
1456 test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
1457 /* clear WS_VSCROLL */
1458 test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
1461 /* test if we receive the right sequence of messages */
1462 static void test_messages(void)
1464 HWND hwnd, hparent, hchild;
1465 HWND hchild2, hbutton;
1466 HMENU hmenu;
1468 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
1469 100, 100, 200, 200, 0, 0, 0, NULL);
1470 ok (hwnd != 0, "Failed to create overlapped window\n");
1471 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
1473 /* test ShowWindow(SW_HIDE) on a newly created invisible window */
1474 ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
1475 ok_sequence(WmHideInvisibleOverlappedSeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
1477 /* test WM_SETREDRAW on a not visible top level window */
1478 test_WM_SETREDRAW(hwnd);
1480 SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
1481 ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
1482 ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
1484 ok(GetActiveWindow() == hwnd, "window should be active\n");
1485 ok(GetFocus() == hwnd, "window should have input focus\n");
1486 ShowWindow(hwnd, SW_HIDE);
1487 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", TRUE);
1489 ShowWindow(hwnd, SW_SHOW);
1490 ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
1492 ok(GetActiveWindow() == hwnd, "window should be active\n");
1493 ok(GetFocus() == hwnd, "window should have input focus\n");
1494 SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
1495 ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
1496 ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
1498 /* test WM_SETREDRAW on a visible top level window */
1499 ShowWindow(hwnd, SW_SHOW);
1500 test_WM_SETREDRAW(hwnd);
1502 trace("testing scroll APIs on a visible top level window %p\n", hwnd);
1503 test_scroll_messages(hwnd);
1505 DestroyWindow(hwnd);
1506 ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
1508 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
1509 100, 100, 200, 200, 0, 0, 0, NULL);
1510 ok (hparent != 0, "Failed to create parent window\n");
1511 flush_sequence();
1513 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
1514 0, 0, 10, 10, hparent, 0, 0, NULL);
1515 ok (hchild != 0, "Failed to create child window\n");
1516 ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
1517 DestroyWindow(hchild);
1518 flush_sequence();
1520 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
1521 0, 0, 10, 10, hparent, 0, 0, NULL);
1522 ok (hchild != 0, "Failed to create child window\n");
1523 ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
1525 trace("testing scroll APIs on a visible child window %p\n", hchild);
1526 test_scroll_messages(hchild);
1528 DestroyWindow(hchild);
1529 flush_sequence();
1531 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
1532 0, 0, 10, 10, hparent, 0, 0, NULL);
1533 ok (hchild != 0, "Failed to create child window\n");
1534 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
1536 hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
1537 100, 100, 50, 50, hparent, 0, 0, NULL);
1538 ok (hchild2 != 0, "Failed to create child2 window\n");
1539 flush_sequence();
1541 hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
1542 0, 100, 50, 50, hchild, 0, 0, NULL);
1543 ok (hbutton != 0, "Failed to create button window\n");
1545 /* test WM_SETREDRAW on a not visible child window */
1546 test_WM_SETREDRAW(hchild);
1548 ShowWindow(hchild, SW_SHOW);
1549 ok_sequence(WmShowChildSeq, "ShowWindow:child", FALSE);
1551 /* test WM_SETREDRAW on a visible child window */
1552 test_WM_SETREDRAW(hchild);
1554 MoveWindow(hchild, 10, 10, 20, 20, TRUE);
1555 ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
1557 ShowWindow(hchild, SW_HIDE);
1558 flush_sequence();
1559 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
1560 ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
1562 ShowWindow(hchild, SW_HIDE);
1563 flush_sequence();
1564 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
1565 ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
1567 /* DestroyWindow sequence below expects that a child has focus */
1568 SetFocus(hchild);
1569 flush_sequence();
1571 DestroyWindow(hchild);
1572 ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
1573 DestroyWindow(hchild2);
1574 DestroyWindow(hbutton);
1576 flush_sequence();
1577 hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
1578 0, 0, 100, 100, hparent, 0, 0, NULL);
1579 ok (hchild != 0, "Failed to create child popup window\n");
1580 ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
1581 DestroyWindow(hchild);
1583 /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
1584 flush_sequence();
1585 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
1586 0, 0, 100, 100, hparent, 0, 0, NULL);
1587 ok (hchild != 0, "Failed to create popup window\n");
1588 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
1589 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
1590 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
1591 flush_sequence();
1592 ShowWindow(hchild, SW_SHOW);
1593 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
1594 flush_sequence();
1595 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
1596 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
1597 flush_sequence();
1598 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
1599 ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
1600 DestroyWindow(hchild);
1602 /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
1603 * changes nothing in message sequences.
1605 flush_sequence();
1606 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
1607 0, 0, 100, 100, hparent, 0, 0, NULL);
1608 ok (hchild != 0, "Failed to create popup window\n");
1609 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
1610 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
1611 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
1612 flush_sequence();
1613 ShowWindow(hchild, SW_SHOW);
1614 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
1615 flush_sequence();
1616 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
1617 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
1618 DestroyWindow(hchild);
1620 flush_sequence();
1621 hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
1622 0, 0, 100, 100, hparent, 0, 0, NULL);
1623 ok(hwnd != 0, "Failed to create custom dialog window\n");
1624 ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
1626 trace("testing scroll APIs on a visible dialog %p\n", hwnd);
1627 test_scroll_messages(hwnd);
1629 flush_sequence();
1630 after_end_dialog = 1;
1631 EndDialog( hwnd, 0 );
1632 ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
1634 DestroyWindow(hwnd);
1635 after_end_dialog = 0;
1637 flush_sequence();
1638 DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
1639 ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
1641 /* test showing child with hidden parent */
1642 ShowWindow( hparent, SW_HIDE );
1643 flush_sequence();
1645 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
1646 0, 0, 10, 10, hparent, 0, 0, NULL);
1647 ok (hchild != 0, "Failed to create child window\n");
1648 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
1650 ShowWindow( hchild, SW_SHOW );
1651 ok_sequence(WmShowChildInvisibleParentSeq, "ShowWindow:show child with invisible parent", TRUE);
1652 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
1653 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
1655 ShowWindow( hchild, SW_HIDE );
1656 ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", TRUE);
1657 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
1658 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
1660 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
1661 ok_sequence(WmShowChildInvisibleParentSeq_2, "SetWindowPos:show child with invisible parent", FALSE);
1662 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
1663 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
1665 SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
1666 ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
1667 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
1668 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
1670 DestroyWindow(hparent);
1671 flush_sequence();
1673 /* Message sequence for SetMenu */
1674 hmenu = CreateMenu();
1675 ok (hmenu != 0, "Failed to create menu\n");
1676 ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
1677 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
1678 100, 100, 200, 200, 0, hmenu, 0, NULL);
1679 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
1680 ok (SetMenu(hwnd, 0), "SetMenu\n");
1681 ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
1682 ok (SetMenu(hwnd, 0), "SetMenu\n");
1683 ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
1684 ShowWindow(hwnd, SW_SHOW);
1685 flush_sequence();
1686 ok (SetMenu(hwnd, 0), "SetMenu\n");
1687 ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", TRUE);
1688 ok (SetMenu(hwnd, hmenu), "SetMenu\n");
1689 ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", TRUE);
1691 ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
1692 ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", TRUE);
1694 DestroyWindow(hwnd);
1695 flush_sequence();
1697 /* Message sequence for EnableWindow */
1698 hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
1699 100, 100, 200, 200, 0, 0, 0, NULL);
1700 ok (hparent != 0, "Failed to create parent window\n");
1701 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
1702 0, 0, 10, 10, hparent, 0, 0, NULL);
1703 ok (hchild != 0, "Failed to create child window\n");
1705 SetFocus(hchild);
1706 flush_sequence();
1708 EnableWindow(hparent, FALSE);
1709 ok_sequence(WmEnableWindowSeq, "EnableWindow", FALSE);
1711 DestroyWindow(hparent);
1712 flush_sequence();
1715 /****************** button message test *************************/
1716 static const struct message WmSetFocusButtonSeq[] =
1718 { HCBT_SETFOCUS, hook },
1719 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1720 { WM_SETFOCUS, sent|wparam, 0 },
1721 { WM_CTLCOLORBTN, sent|defwinproc },
1722 { 0 }
1724 static const struct message WmKillFocusButtonSeq[] =
1726 { HCBT_SETFOCUS, hook },
1727 { WM_KILLFOCUS, sent|wparam, 0 },
1728 { WM_CTLCOLORBTN, sent|defwinproc },
1729 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1730 { 0 }
1732 static const struct message WmSetFocusStaticSeq[] =
1734 { HCBT_SETFOCUS, hook },
1735 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1736 { WM_SETFOCUS, sent|wparam, 0 },
1737 { WM_CTLCOLORSTATIC, sent|defwinproc },
1738 { 0 }
1740 static const struct message WmKillFocusStaticSeq[] =
1742 { HCBT_SETFOCUS, hook },
1743 { WM_KILLFOCUS, sent|wparam, 0 },
1744 { WM_CTLCOLORSTATIC, sent|defwinproc },
1745 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1746 { 0 }
1748 static const struct message WmLButtonDownSeq[] =
1750 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
1751 { HCBT_SETFOCUS, hook },
1752 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1753 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
1754 { WM_CTLCOLORBTN, sent|defwinproc },
1755 { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
1756 { WM_CTLCOLORBTN, sent|defwinproc },
1757 { 0 }
1759 static const struct message WmLButtonUpSeq[] =
1761 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
1762 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
1763 { WM_CTLCOLORBTN, sent|defwinproc },
1764 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
1765 { 0 }
1768 static WNDPROC old_button_proc;
1770 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1772 static long defwndproc_counter = 0;
1773 LRESULT ret;
1774 struct message msg;
1776 trace("button: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1778 msg.message = message;
1779 msg.flags = sent|wparam|lparam;
1780 if (defwndproc_counter) msg.flags |= defwinproc;
1781 msg.wParam = wParam;
1782 msg.lParam = lParam;
1783 add_message(&msg);
1785 if (message == BM_SETSTATE)
1786 ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
1788 defwndproc_counter++;
1789 ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
1790 defwndproc_counter--;
1792 return ret;
1795 static void subclass_button(void)
1797 WNDCLASSA cls;
1799 if (!GetClassInfoA(0, "button", &cls)) assert(0);
1801 old_button_proc = cls.lpfnWndProc;
1803 cls.hInstance = GetModuleHandle(0);
1804 cls.lpfnWndProc = button_hook_proc;
1805 cls.lpszClassName = "my_button_class";
1806 if (!RegisterClassA(&cls)) assert(0);
1809 static void test_button_messages(void)
1811 static const struct
1813 DWORD style;
1814 const struct message *setfocus;
1815 const struct message *killfocus;
1816 } button[] = {
1817 { BS_PUSHBUTTON, WmSetFocusButtonSeq, WmKillFocusButtonSeq },
1818 { BS_DEFPUSHBUTTON, WmSetFocusButtonSeq, WmKillFocusButtonSeq },
1819 { BS_CHECKBOX, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
1820 { BS_AUTOCHECKBOX, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
1821 { BS_RADIOBUTTON, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
1822 { BS_3STATE, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
1823 { BS_AUTO3STATE, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
1824 { BS_GROUPBOX, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
1825 { BS_USERBUTTON, WmSetFocusButtonSeq, WmKillFocusButtonSeq },
1826 { BS_AUTORADIOBUTTON, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
1827 { BS_OWNERDRAW, WmSetFocusButtonSeq, WmKillFocusButtonSeq }
1829 int i;
1830 HWND hwnd;
1832 subclass_button();
1834 for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
1836 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP,
1837 0, 0, 50, 14, 0, 0, 0, NULL);
1838 ok(hwnd != 0, "Failed to create button window\n");
1840 ShowWindow(hwnd, SW_SHOW);
1841 UpdateWindow(hwnd);
1842 SetFocus(0);
1843 flush_sequence();
1845 trace("button style %08lx\n", button[i].style);
1846 SetFocus(hwnd);
1847 ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
1849 SetFocus(0);
1850 ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
1852 DestroyWindow(hwnd);
1855 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP | WS_VISIBLE,
1856 0, 0, 50, 14, 0, 0, 0, NULL);
1857 ok(hwnd != 0, "Failed to create button window\n");
1859 SetFocus(0);
1860 flush_sequence();
1862 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
1863 ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
1865 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
1866 ok_sequence(WmLButtonUpSeq, "WM_LBUTTONDOWN on a button", FALSE);
1867 DestroyWindow(hwnd);
1870 /************* painting message test ********************/
1872 static void dump_region(HRGN hrgn)
1874 DWORD i, size;
1875 RGNDATA *data = NULL;
1876 RECT *rect;
1878 if (!hrgn)
1880 printf( "null region\n" );
1881 return;
1883 if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
1884 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
1885 GetRegionData( hrgn, size, data );
1886 printf("%ld rects:", data->rdh.nCount );
1887 for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
1888 printf( " (%ld,%ld)-(%ld,%ld)", rect->left, rect->top, rect->right, rect->bottom );
1889 printf("\n");
1890 HeapFree( GetProcessHeap(), 0, data );
1893 static void check_update_rgn( HWND hwnd, HRGN hrgn )
1895 INT ret;
1896 RECT r1, r2;
1897 HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
1898 HRGN update = CreateRectRgn( 0, 0, 0, 0 );
1900 ret = GetUpdateRgn( hwnd, update, FALSE );
1901 ok( ret != ERROR, "GetUpdateRgn failed\n" );
1902 if (ret == NULLREGION)
1904 ok( !hrgn, "Update region shouldn't be empty\n" );
1906 else
1908 if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
1910 ok( 0, "Regions are different\n" );
1911 if (winetest_debug > 0)
1913 printf( "Update region: " );
1914 dump_region( update );
1915 printf( "Wanted region: " );
1916 dump_region( hrgn );
1920 GetRgnBox( update, &r1 );
1921 GetUpdateRect( hwnd, &r2, FALSE );
1922 ok( r1.left == r2.left && r1.top == r2.top && r1.right == r2.right && r1.bottom == r2.bottom,
1923 "Rectangles are different: %ld,%ld-%ld,%ld / %ld,%ld-%ld,%ld\n",
1924 r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom );
1926 DeleteObject( tmp );
1927 DeleteObject( update );
1930 static const struct message WmInvalidateRgn[] = {
1931 { WM_NCPAINT, sent },
1932 { WM_GETTEXT, sent|defwinproc|optional },
1933 { 0 }
1936 static const struct message WmInvalidateFull[] = {
1937 { WM_NCPAINT, sent|wparam, 1 },
1938 { WM_GETTEXT, sent|defwinproc|optional },
1939 { 0 }
1942 static const struct message WmInvalidateErase[] = {
1943 { WM_NCPAINT, sent|wparam, 1 },
1944 { WM_GETTEXT, sent|defwinproc|optional },
1945 { WM_ERASEBKGND, sent },
1946 { 0 }
1949 static const struct message WmInvalidatePaint[] = {
1950 { WM_PAINT, sent },
1951 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
1952 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
1953 { 0 }
1956 static const struct message WmInvalidateErasePaint[] = {
1957 { WM_PAINT, sent },
1958 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
1959 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
1960 { WM_ERASEBKGND, sent|beginpaint },
1961 { 0 }
1964 static const struct message WmErase[] = {
1965 { WM_ERASEBKGND, sent },
1966 { 0 }
1969 static const struct message WmPaint[] = {
1970 { WM_PAINT, sent },
1971 { 0 }
1974 static void test_paint_messages(void)
1976 RECT rect;
1977 MSG msg;
1978 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
1979 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
1980 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
1981 100, 100, 200, 200, 0, 0, 0, NULL);
1982 ok (hwnd != 0, "Failed to create overlapped window\n");
1984 ShowWindow( hwnd, SW_SHOW );
1985 UpdateWindow( hwnd );
1986 check_update_rgn( hwnd, 0 );
1987 SetRectRgn( hrgn, 10, 10, 20, 20 );
1988 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
1989 check_update_rgn( hwnd, hrgn );
1990 SetRectRgn( hrgn2, 20, 20, 30, 30 );
1991 RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
1992 CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
1993 check_update_rgn( hwnd, hrgn );
1994 /* validate everything */
1995 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
1996 check_update_rgn( hwnd, 0 );
1997 /* now with frame */
1998 SetRectRgn( hrgn, -5, -5, 20, 20 );
2000 flush_sequence();
2001 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
2002 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
2004 SetRectRgn( hrgn, 0, 0, 20, 20 ); /* GetUpdateRgn clips to client area */
2005 check_update_rgn( hwnd, hrgn );
2007 flush_sequence();
2008 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
2009 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
2011 flush_sequence();
2012 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
2013 ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
2015 GetClientRect( hwnd, &rect );
2016 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
2017 check_update_rgn( hwnd, hrgn );
2019 flush_sequence();
2020 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
2021 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
2023 flush_sequence();
2024 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
2025 ok_sequence( WmInvalidatePaint, "InvalidatePaint", TRUE );
2026 check_update_rgn( hwnd, 0 );
2028 flush_sequence();
2029 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
2030 ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
2031 check_update_rgn( hwnd, 0 );
2033 flush_sequence();
2034 SetRectRgn( hrgn, 0, 0, 100, 100 );
2035 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
2036 SetRectRgn( hrgn, 0, 0, 50, 100 );
2037 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
2038 SetRectRgn( hrgn, 50, 0, 100, 100 );
2039 check_update_rgn( hwnd, hrgn );
2040 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
2041 ok_sequence( WmEmptySeq, "EmptySeq", FALSE ); /* must not generate messages, everything is valid */
2042 check_update_rgn( hwnd, 0 );
2044 flush_sequence();
2045 SetRectRgn( hrgn, 0, 0, 100, 100 );
2046 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
2047 SetRectRgn( hrgn, 0, 0, 100, 50 );
2048 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
2049 ok_sequence( WmErase, "Erase", FALSE );
2050 SetRectRgn( hrgn, 0, 50, 100, 100 );
2051 check_update_rgn( hwnd, hrgn );
2053 flush_sequence();
2054 SetRectRgn( hrgn, 0, 0, 100, 100 );
2055 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
2056 SetRectRgn( hrgn, 0, 0, 50, 50 );
2057 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
2058 ok_sequence( WmPaint, "Paint", FALSE );
2060 flush_sequence();
2061 SetRectRgn( hrgn, -4, -4, -2, -2 );
2062 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
2063 SetRectRgn( hrgn, -4, -4, -3, -3 );
2064 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
2065 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
2067 flush_sequence();
2068 SetRectRgn( hrgn, -4, -4, -2, -2 );
2069 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
2070 SetRectRgn( hrgn, -4, -4, -3, -3 );
2071 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
2072 SetRectRgn( hrgn, 0, 0, 1, 1 );
2073 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
2074 ok_sequence( WmPaint, "Paint", TRUE );
2076 flush_sequence();
2077 SetRectRgn( hrgn, -4, -4, -1, -1 );
2078 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
2079 RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
2080 /* make sure no WM_PAINT was generated */
2081 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
2082 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
2084 flush_sequence();
2085 SetRectRgn( hrgn, -4, -4, -1, -1 );
2086 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
2087 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
2089 if (msg.hwnd == hwnd && msg.message == WM_PAINT)
2091 /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
2092 INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
2093 ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
2094 ret = GetUpdateRect( hwnd, &rect, FALSE );
2095 ok( ret, "Invalid GetUpdateRect result %d\n", ret );
2096 /* this will send WM_NCPAINT and validate the non client area */
2097 ret = GetUpdateRect( hwnd, &rect, TRUE );
2098 ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
2100 else DispatchMessage( &msg );
2102 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
2104 DeleteObject( hrgn );
2105 DeleteObject( hrgn2 );
2106 DestroyWindow( hwnd );
2110 /************* window procedures ********************/
2112 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2114 static long defwndproc_counter = 0;
2115 static long beginpaint_counter = 0;
2116 LRESULT ret;
2117 struct message msg;
2119 trace("%p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2121 msg.message = message;
2122 msg.flags = sent|wparam|lparam;
2123 if (defwndproc_counter) msg.flags |= defwinproc;
2124 if (beginpaint_counter) msg.flags |= beginpaint;
2125 msg.wParam = wParam;
2126 msg.lParam = lParam;
2127 add_message(&msg);
2129 if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
2131 HWND parent = GetParent(hwnd);
2132 RECT rc;
2133 MINMAXINFO *minmax = (MINMAXINFO *)lParam;
2135 GetClientRect(parent, &rc);
2136 trace("parent %p client size = (%ld x %ld)\n", parent, rc.right, rc.bottom);
2138 trace("ptReserved = (%ld,%ld)\n"
2139 "ptMaxSize = (%ld,%ld)\n"
2140 "ptMaxPosition = (%ld,%ld)\n"
2141 "ptMinTrackSize = (%ld,%ld)\n"
2142 "ptMaxTrackSize = (%ld,%ld)\n",
2143 minmax->ptReserved.x, minmax->ptReserved.y,
2144 minmax->ptMaxSize.x, minmax->ptMaxSize.y,
2145 minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
2146 minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
2147 minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
2149 ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %ld != %ld\n",
2150 minmax->ptMaxSize.x, rc.right);
2151 ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %ld != %ld\n",
2152 minmax->ptMaxSize.y, rc.bottom);
2155 if (message == WM_PAINT)
2157 PAINTSTRUCT ps;
2158 beginpaint_counter++;
2159 BeginPaint( hwnd, &ps );
2160 beginpaint_counter--;
2161 EndPaint( hwnd, &ps );
2162 return 0;
2165 defwndproc_counter++;
2166 ret = DefWindowProcA(hwnd, message, wParam, lParam);
2167 defwndproc_counter--;
2169 return ret;
2172 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2174 static long defwndproc_counter = 0;
2175 LRESULT ret;
2176 struct message msg;
2178 trace("popup: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2180 msg.message = message;
2181 msg.flags = sent|wparam|lparam;
2182 if (defwndproc_counter) msg.flags |= defwinproc;
2183 msg.wParam = wParam;
2184 msg.lParam = lParam;
2185 add_message(&msg);
2187 if (message == WM_CREATE)
2189 DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
2190 SetWindowLongA(hwnd, GWL_STYLE, style);
2193 defwndproc_counter++;
2194 ret = DefWindowProcA(hwnd, message, wParam, lParam);
2195 defwndproc_counter--;
2197 return ret;
2200 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2202 static long defwndproc_counter = 0;
2203 LRESULT ret;
2204 struct message msg;
2206 trace("parent: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2208 if (message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
2209 message == WM_SETFOCUS || message == WM_KILLFOCUS ||
2210 message == WM_ENABLE || message == WM_ENTERIDLE ||
2211 message == WM_IME_SETCONTEXT)
2213 msg.message = message;
2214 msg.flags = sent|parent|wparam|lparam;
2215 if (defwndproc_counter) msg.flags |= defwinproc;
2216 msg.wParam = wParam;
2217 msg.lParam = lParam;
2218 add_message(&msg);
2221 defwndproc_counter++;
2222 ret = DefWindowProcA(hwnd, message, wParam, lParam);
2223 defwndproc_counter--;
2225 return ret;
2228 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2230 static long defwndproc_counter = 0;
2231 LRESULT ret;
2232 struct message msg;
2234 trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2236 DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
2237 ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
2238 if (after_end_dialog)
2239 ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
2240 else
2241 ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
2243 msg.message = message;
2244 msg.flags = sent|wparam|lparam;
2245 if (defwndproc_counter) msg.flags |= defwinproc;
2246 msg.wParam = wParam;
2247 msg.lParam = lParam;
2248 add_message(&msg);
2250 defwndproc_counter++;
2251 ret = DefDlgProcA(hwnd, message, wParam, lParam);
2252 defwndproc_counter--;
2254 return ret;
2257 static BOOL RegisterWindowClasses(void)
2259 WNDCLASSA cls;
2261 cls.style = 0;
2262 cls.lpfnWndProc = MsgCheckProcA;
2263 cls.cbClsExtra = 0;
2264 cls.cbWndExtra = 0;
2265 cls.hInstance = GetModuleHandleA(0);
2266 cls.hIcon = 0;
2267 cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
2268 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
2269 cls.lpszMenuName = NULL;
2270 cls.lpszClassName = "TestWindowClass";
2271 if(!RegisterClassA(&cls)) return FALSE;
2273 cls.lpfnWndProc = PopupMsgCheckProcA;
2274 cls.lpszClassName = "TestPopupClass";
2275 if(!RegisterClassA(&cls)) return FALSE;
2277 cls.lpfnWndProc = ParentMsgCheckProcA;
2278 cls.lpszClassName = "TestParentClass";
2279 if(!RegisterClassA(&cls)) return FALSE;
2281 cls.lpfnWndProc = DefWindowProcA;
2282 cls.lpszClassName = "SimpleWindowClass";
2283 if(!RegisterClassA(&cls)) return FALSE;
2285 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
2286 cls.lpfnWndProc = TestDlgProcA;
2287 cls.lpszClassName = "TestDialogClass";
2288 if(!RegisterClassA(&cls)) return FALSE;
2290 return TRUE;
2293 static HHOOK hCBT_hook;
2295 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
2297 char buf[256];
2299 trace("CBT: %d, %08x, %08lx\n", nCode, wParam, lParam);
2301 /* Log also SetFocus(0) calls */
2302 if (!wParam) wParam = lParam;
2304 if (GetClassNameA((HWND)wParam, buf, sizeof(buf)))
2306 if (!strcmp(buf, "TestWindowClass") ||
2307 !strcmp(buf, "TestParentClass") ||
2308 !strcmp(buf, "TestPopupClass") ||
2309 !strcmp(buf, "SimpleWindowClass") ||
2310 !strcmp(buf, "TestDialogClass") ||
2311 !strcmp(buf, "MDI_frame_class") ||
2312 !strcmp(buf, "MDI_client_class") ||
2313 !strcmp(buf, "MDI_child_class") ||
2314 !strcmp(buf, "my_button_class") ||
2315 !strcmp(buf, "#32770"))
2317 struct message msg;
2319 msg.message = nCode;
2320 msg.flags = hook;
2321 msg.wParam = wParam;
2322 msg.lParam = lParam;
2323 add_message(&msg);
2326 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
2329 START_TEST(msg)
2331 if (!RegisterWindowClasses()) assert(0);
2333 hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
2334 assert(hCBT_hook);
2336 test_messages();
2337 test_mdi_messages();
2338 test_button_messages();
2339 test_paint_messages();
2341 UnhookWindowsHookEx(hCBT_hook);