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
27 #define _WIN32_WINNT 0x0500 /* For WM_CHANGEUISTATE */
34 #include "wine/test.h"
36 #define MDI_FIRST_CHILD_ID 2004
38 /* undocumented SWP flags - from SDK 3.1 */
39 #define SWP_NOCLIENTSIZE 0x0800
40 #define SWP_NOCLIENTMOVE 0x1000
43 FIXME: add tests for these
44 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
45 WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
46 WS_THICKFRAME: thick border
47 WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
48 WS_BORDER (default for overlapped windows): single black border
49 none (default for child (and popup?) windows): no border
65 UINT message; /* the WM_* code */
66 msg_flags_t flags; /* message props */
67 WPARAM wParam; /* expected value of wParam */
68 LPARAM lParam; /* expected value of lParam */
71 /* Empty message sequence */
72 static const struct message WmEmptySeq[] =
76 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
77 static const struct message WmCreateOverlappedSeq[] = {
78 { HCBT_CREATEWND, hook },
79 { WM_GETMINMAXINFO, sent },
80 { WM_NCCREATE, sent },
81 { WM_NCCALCSIZE, sent|wparam, 0 },
85 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
86 * for a not visible overlapped window.
88 static const struct message WmSWP_ShowOverlappedSeq[] = {
89 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
90 { WM_NCPAINT, sent|wparam|optional, 1 },
91 { WM_GETTEXT, sent|defwinproc|optional },
92 { WM_ERASEBKGND, sent|optional },
93 { HCBT_ACTIVATE, hook },
94 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
95 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
96 { WM_ACTIVATEAPP, sent|wparam, 1 },
97 { WM_NCACTIVATE, sent|wparam, 1 },
98 { WM_GETTEXT, sent|defwinproc|optional },
99 { WM_ACTIVATE, sent|wparam, 1 },
100 { HCBT_SETFOCUS, hook },
101 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
102 { WM_IME_NOTIFY, sent|defwinproc|optional },
103 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
104 { WM_NCPAINT, sent|wparam|optional, 1 },
105 { WM_GETTEXT, sent|defwinproc|optional },
106 { WM_ERASEBKGND, sent|optional },
107 /* Win9x adds SWP_NOZORDER below */
108 { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
109 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
110 { WM_NCPAINT, sent|wparam|optional, 1 },
111 { WM_ERASEBKGND, sent|optional },
114 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
115 * for a visible overlapped window.
117 static const struct message WmSWP_HideOverlappedSeq[] = {
118 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
119 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
122 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
123 static const struct message WmShowOverlappedSeq[] = {
124 { WM_SHOWWINDOW, sent|wparam, 1 },
125 { WM_NCPAINT, sent|wparam|optional, 1 },
126 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
127 { WM_NCPAINT, sent|wparam|optional, 1 },
128 { WM_GETTEXT, sent|defwinproc|optional },
129 { WM_ERASEBKGND, sent|optional },
130 { HCBT_ACTIVATE, hook },
131 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
132 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
133 { WM_ACTIVATEAPP, sent|wparam, 1 },
134 { WM_NCACTIVATE, sent|wparam, 1 },
135 { WM_GETTEXT, sent|defwinproc|optional },
136 { WM_ACTIVATE, sent|wparam, 1 },
137 { HCBT_SETFOCUS, hook },
138 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
139 { WM_IME_NOTIFY, sent|defwinproc|optional },
140 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
141 { WM_NCPAINT, sent|wparam|optional, 1 },
142 { WM_GETTEXT, sent|defwinproc|optional },
143 { WM_ERASEBKGND, sent|optional },
144 /* Win9x adds SWP_NOZORDER below */
145 { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
146 { WM_NCCALCSIZE, sent|optional },
147 { WM_NCPAINT, sent|optional },
148 { WM_ERASEBKGND, sent|optional },
149 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
150 * messages. Does that mean that CreateWindow doesn't set initial
151 * window dimensions for overlapped windows?
158 /* ShowWindow(SW_HIDE) for a visible overlapped window */
159 static const struct message WmHideOverlappedSeq[] = {
160 { WM_SHOWWINDOW, sent|wparam, 0 },
161 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
162 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
165 { WM_NCACTIVATE, sent|wparam, 0 },
166 { WM_ACTIVATE, sent|wparam, 0 },
167 { WM_ACTIVATEAPP, sent|wparam, 0 },
168 { WM_KILLFOCUS, sent|wparam, 0 },
169 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
170 { WM_IME_NOTIFY, sent|optional|defwinproc },
173 /* ShowWindow(SW_HIDE) for an invisible overlapped window */
174 static const struct message WmHideInvisibleOverlappedSeq[] = {
177 /* DestroyWindow for a visible overlapped window */
178 static const struct message WmDestroyOverlappedSeq[] = {
179 { HCBT_DESTROYWND, hook },
180 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
181 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
182 { WM_NCACTIVATE, sent|wparam, 0 },
183 { WM_ACTIVATE, sent|wparam, 0 },
184 { WM_ACTIVATEAPP, sent|wparam, 0 },
185 { WM_KILLFOCUS, sent|wparam, 0 },
186 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
187 { WM_IME_NOTIFY, sent|optional|defwinproc },
188 { WM_DESTROY, sent },
189 { WM_NCDESTROY, sent },
192 /* CreateWindow (for a child popup window, not initially visible) */
193 static const struct message WmCreateChildPopupSeq[] = {
194 { HCBT_CREATEWND, hook },
195 { WM_NCCREATE, sent },
196 { WM_NCCALCSIZE, sent|wparam, 0 },
202 /* CreateWindow (for a popup window, not initially visible,
203 * which sets WS_VISIBLE in WM_CREATE handler)
205 static const struct message WmCreateInvisiblePopupSeq[] = {
206 { HCBT_CREATEWND, hook },
207 { WM_NCCREATE, sent },
208 { WM_NCCALCSIZE, sent|wparam, 0 },
210 { WM_STYLECHANGING, sent },
211 { WM_STYLECHANGED, sent },
216 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
217 * for a popup window with WS_VISIBLE style set
219 static const struct message WmShowVisiblePopupSeq_2[] = {
220 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
223 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
224 * for a popup window with WS_VISIBLE style set
226 static const struct message WmShowVisiblePopupSeq_3[] = {
227 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
228 { HCBT_ACTIVATE, hook },
229 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
230 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
231 { WM_NCACTIVATE, sent|wparam, 1 },
232 { WM_ACTIVATE, sent|wparam, 1 },
233 { HCBT_SETFOCUS, hook },
234 { WM_KILLFOCUS, sent|parent },
235 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
236 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
237 { WM_IME_NOTIFY, sent|defwinproc|optional },
238 { WM_SETFOCUS, sent|defwinproc },
241 /* CreateWindow (for child window, not initially visible) */
242 static const struct message WmCreateChildSeq[] = {
243 { HCBT_CREATEWND, hook },
244 { WM_NCCREATE, sent },
245 /* child is inserted into parent's child list after WM_NCCREATE returns */
246 { WM_NCCALCSIZE, sent|wparam, 0 },
250 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
253 /* CreateWindow (for maximized child window, not initially visible) */
254 static const struct message WmCreateMaximizedChildSeq[] = {
255 { HCBT_CREATEWND, hook },
256 { WM_NCCREATE, sent },
257 { WM_NCCALCSIZE, sent|wparam, 0 },
261 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
262 { WM_GETMINMAXINFO, sent },
263 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
264 { WM_NCCALCSIZE, sent|wparam, 1 },
265 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTMOVE|0x8000 },
266 { WM_SIZE, sent|defwinproc },
267 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
270 /* CreateWindow (for a child window, initially visible) */
271 static const struct message WmCreateVisibleChildSeq[] = {
272 { HCBT_CREATEWND, hook },
273 { WM_NCCREATE, sent },
274 /* child is inserted into parent's child list after WM_NCCREATE returns */
275 { WM_NCCALCSIZE, sent|wparam, 0 },
279 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
280 { WM_SHOWWINDOW, sent|wparam, 1 },
281 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER },
282 { WM_ERASEBKGND, sent|parent|optional },
283 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
286 /* ShowWindow(SW_SHOW) for a not visible child window */
287 static const struct message WmShowChildSeq[] = {
288 { WM_SHOWWINDOW, sent|wparam, 1 },
289 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
290 { WM_ERASEBKGND, sent|parent|optional },
291 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
294 /* ShowWindow(SW_HIDE) for a visible child window */
295 static const struct message WmHideChildSeq[] = {
296 { WM_SHOWWINDOW, sent|wparam, 0 },
297 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
298 { WM_ERASEBKGND, sent|parent|optional },
299 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
302 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
303 * for a not visible child window
305 static const struct message WmShowChildSeq_2[] = {
306 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
307 { WM_CHILDACTIVATE, sent },
308 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
311 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
312 * for a not visible child window
314 static const struct message WmShowChildSeq_3[] = {
315 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
316 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
319 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
320 * for a visible child window with a caption
322 static const struct message WmShowChildSeq_4[] = {
323 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
324 { WM_CHILDACTIVATE, sent },
327 /* ShowWindow(SW_SHOW) for child with invisible parent */
328 static const struct message WmShowChildInvisibleParentSeq[] = {
329 { WM_SHOWWINDOW, sent|wparam, 1 },
332 /* ShowWindow(SW_HIDE) for child with invisible parent */
333 static const struct message WmHideChildInvisibleParentSeq[] = {
334 { WM_SHOWWINDOW, sent|wparam, 0 },
337 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
338 static const struct message WmShowChildInvisibleParentSeq_2[] = {
339 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER },
340 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
343 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
344 static const struct message WmHideChildInvisibleParentSeq_2[] = {
345 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
346 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
349 /* DestroyWindow for a visible child window */
350 static const struct message WmDestroyChildSeq[] = {
351 { HCBT_DESTROYWND, hook },
352 { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
353 { WM_SHOWWINDOW, sent|wparam, 0 },
354 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
355 { WM_ERASEBKGND, sent|parent|optional },
356 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
357 { HCBT_SETFOCUS, hook }, /* set focus to a parent */
358 { WM_KILLFOCUS, sent },
359 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
360 { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
361 { WM_SETFOCUS, sent|parent },
362 { WM_DESTROY, sent },
363 { WM_DESTROY, sent|optional }, /* a bug in win2k sp4 ? */
364 { WM_NCDESTROY, sent },
365 { WM_NCDESTROY, sent|optional }, /* a bug in win2k sp4 ? */
368 /* Moving the mouse in nonclient area */
369 static const struct message WmMouseMoveInNonClientAreaSeq[] = { /* FIXME: add */
370 { WM_NCHITTEST, sent },
371 { WM_SETCURSOR, sent },
372 { WM_NCMOUSEMOVE, posted },
375 /* Moving the mouse in client area */
376 static const struct message WmMouseMoveInClientAreaSeq[] = { /* FIXME: add */
377 { WM_NCHITTEST, sent },
378 { WM_SETCURSOR, sent },
379 { WM_MOUSEMOVE, posted },
382 /* Moving by dragging the title bar (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
383 static const struct message WmDragTitleBarSeq[] = { /* FIXME: add */
384 { WM_NCLBUTTONDOWN, sent|wparam, HTCAPTION },
385 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_MOVE+2 },
386 { WM_GETMINMAXINFO, sent|defwinproc },
387 { WM_ENTERSIZEMOVE, sent|defwinproc },
388 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
389 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
390 { WM_MOVE, sent|defwinproc },
391 { WM_EXITSIZEMOVE, sent|defwinproc },
394 /* Sizing by dragging the thick borders (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
395 static const struct message WmDragThickBordersBarSeq[] = { /* FIXME: add */
396 { WM_NCLBUTTONDOWN, sent|wparam, 0xd },
397 { WM_SYSCOMMAND, sent|defwinproc|wparam, 0xf004 },
398 { WM_GETMINMAXINFO, sent|defwinproc },
399 { WM_ENTERSIZEMOVE, sent|defwinproc },
400 { WM_SIZING, sent|defwinproc|wparam, 4}, /* one for each mouse movement */
401 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
402 { WM_GETMINMAXINFO, sent|defwinproc },
403 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
404 { WM_NCPAINT, sent|defwinproc|wparam, 1 },
405 { WM_GETTEXT, sent|defwinproc },
406 { WM_ERASEBKGND, sent|defwinproc },
407 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
408 { WM_MOVE, sent|defwinproc },
409 { WM_SIZE, sent|defwinproc },
410 { WM_EXITSIZEMOVE, sent|defwinproc },
413 /* Resizing child window with MoveWindow (32) */
414 static const struct message WmResizingChildWithMoveWindowSeq[] = {
415 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
416 { WM_NCCALCSIZE, sent|wparam, 1 },
417 { WM_ERASEBKGND, sent|optional },
418 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
419 { WM_MOVE, sent|defwinproc },
420 { WM_SIZE, sent|defwinproc },
423 /* Clicking on inactive button */
424 static const struct message WmClickInactiveButtonSeq[] = { /* FIXME: add */
425 { WM_NCHITTEST, sent },
426 { WM_PARENTNOTIFY, sent|parent|wparam, WM_LBUTTONDOWN },
427 { WM_MOUSEACTIVATE, sent },
428 { WM_MOUSEACTIVATE, sent|parent|defwinproc },
429 { WM_SETCURSOR, sent },
430 { WM_SETCURSOR, sent|parent|defwinproc },
431 { WM_LBUTTONDOWN, posted },
432 { WM_KILLFOCUS, posted|parent },
433 { WM_SETFOCUS, posted },
434 { WM_CTLCOLORBTN, posted|parent },
435 { BM_SETSTATE, posted },
436 { WM_CTLCOLORBTN, posted|parent },
437 { WM_LBUTTONUP, posted },
438 { BM_SETSTATE, posted },
439 { WM_CTLCOLORBTN, posted|parent },
440 { WM_COMMAND, posted|parent },
443 /* Reparenting a button (16/32) */
444 /* The last child (button) reparented gets topmost for its new parent. */
445 static const struct message WmReparentButtonSeq[] = { /* FIXME: add */
446 { WM_SHOWWINDOW, sent|wparam, 0 },
447 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER },
448 { WM_ERASEBKGND, sent|parent },
449 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER },
450 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOZORDER },
451 { WM_CHILDACTIVATE, sent },
452 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW|SWP_NOZORDER },
453 { WM_MOVE, sent|defwinproc },
454 { WM_SHOWWINDOW, sent|wparam, 1 },
457 /* Creation of a custom dialog (32) */
458 static const struct message WmCreateCustomDialogSeq[] = {
459 { HCBT_CREATEWND, hook },
460 { WM_GETMINMAXINFO, sent },
461 { WM_NCCREATE, sent },
462 { WM_NCCALCSIZE, sent|wparam, 0 },
464 { WM_SHOWWINDOW, sent|wparam, 1 },
465 { HCBT_ACTIVATE, hook },
466 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
467 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
468 { WM_NCACTIVATE, sent|wparam, 1 },
469 { WM_GETTEXT, sent|optional|defwinproc },
470 { WM_GETICON, sent|optional|defwinproc },
471 { WM_GETICON, sent|optional|defwinproc },
472 { WM_GETICON, sent|optional|defwinproc },
473 { WM_GETTEXT, sent|optional|defwinproc },
474 { WM_ACTIVATE, sent|wparam, 1 },
475 { WM_KILLFOCUS, sent|parent },
476 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
477 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
478 { WM_IME_NOTIFY, sent|optional|defwinproc },
479 { WM_SETFOCUS, sent },
480 { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
481 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
482 { WM_NCPAINT, sent|wparam, 1 },
483 { WM_GETTEXT, sent|optional|defwinproc },
484 { WM_GETICON, sent|optional|defwinproc },
485 { WM_GETICON, sent|optional|defwinproc },
486 { WM_GETICON, sent|optional|defwinproc },
487 { WM_GETTEXT, sent|optional|defwinproc },
488 { WM_ERASEBKGND, sent },
489 { WM_CTLCOLORDLG, sent|defwinproc },
490 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
491 { WM_GETTEXT, sent|optional },
492 { WM_GETICON, sent|optional },
493 { WM_GETICON, sent|optional },
494 { WM_GETICON, sent|optional },
495 { WM_GETTEXT, sent|optional },
496 { WM_NCCALCSIZE, sent|optional },
497 { WM_NCPAINT, sent|optional },
498 { WM_GETTEXT, sent|optional|defwinproc },
499 { WM_GETICON, sent|optional|defwinproc },
500 { WM_GETICON, sent|optional|defwinproc },
501 { WM_GETICON, sent|optional|defwinproc },
502 { WM_GETTEXT, sent|optional|defwinproc },
503 { WM_ERASEBKGND, sent|optional },
504 { WM_CTLCOLORDLG, sent|optional|defwinproc },
509 /* Calling EndDialog for a custom dialog (32) */
510 static const struct message WmEndCustomDialogSeq[] = {
511 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
512 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
513 { WM_GETTEXT, sent|optional },
514 { WM_GETICON, sent|optional },
515 { WM_GETICON, sent|optional },
516 { WM_GETICON, sent|optional },
517 { HCBT_ACTIVATE, hook },
518 { WM_NCACTIVATE, sent|wparam, 0 },
519 { WM_GETTEXT, sent|optional|defwinproc },
520 { WM_GETICON, sent|optional|defwinproc },
521 { WM_GETICON, sent|optional|defwinproc },
522 { WM_GETICON, sent|optional|defwinproc },
523 { WM_GETTEXT, sent|optional|defwinproc },
524 { WM_ACTIVATE, sent|wparam, 0 },
525 { WM_WINDOWPOSCHANGING, sent|wparam|optional, 0 },
526 { HCBT_SETFOCUS, hook },
527 { WM_KILLFOCUS, sent },
528 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
529 { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
530 { WM_IME_NOTIFY, sent|optional },
531 { WM_SETFOCUS, sent|parent|defwinproc },
534 /* Creation and destruction of a modal dialog (32) */
535 static const struct message WmModalDialogSeq[] = {
536 { WM_CANCELMODE, sent|parent },
537 { HCBT_SETFOCUS, hook },
538 { WM_KILLFOCUS, sent|parent },
539 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
540 { WM_ENABLE, sent|parent|wparam, 0 },
541 { HCBT_CREATEWND, hook },
542 { WM_SETFONT, sent },
543 { WM_INITDIALOG, sent },
544 { WM_CHANGEUISTATE, sent|optional },
545 { WM_SHOWWINDOW, sent },
546 { HCBT_ACTIVATE, hook },
547 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
548 { WM_NCACTIVATE, sent|wparam, 1 },
549 { WM_GETICON, sent|optional },
550 { WM_GETICON, sent|optional },
551 { WM_GETICON, sent|optional },
552 { WM_GETTEXT, sent|optional },
553 { WM_ACTIVATE, sent|wparam, 1 },
554 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
555 { WM_NCPAINT, sent },
556 { WM_GETICON, sent|optional },
557 { WM_GETICON, sent|optional },
558 { WM_GETICON, sent|optional },
559 { WM_GETTEXT, sent|optional },
560 { WM_ERASEBKGND, sent },
561 { WM_CTLCOLORDLG, sent },
562 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
563 { WM_GETICON, sent|optional },
564 { WM_GETICON, sent|optional },
565 { WM_GETICON, sent|optional },
566 { WM_GETTEXT, sent|optional },
567 { WM_NCCALCSIZE, sent|optional },
568 { WM_NCPAINT, sent|optional },
569 { WM_GETICON, sent|optional },
570 { WM_GETICON, sent|optional },
571 { WM_GETICON, sent|optional },
572 { WM_GETTEXT, sent|optional },
573 { WM_ERASEBKGND, sent|optional },
574 { WM_CTLCOLORDLG, sent|optional },
575 { WM_PAINT, sent|optional },
576 { WM_CTLCOLORBTN, sent },
577 { WM_ENTERIDLE, sent|parent|optional },
579 { WM_ENABLE, sent|parent|wparam, 1 },
580 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
581 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
582 { WM_GETICON, sent|optional },
583 { WM_GETICON, sent|optional },
584 { WM_GETICON, sent|optional },
585 { WM_GETTEXT, sent|optional },
586 { HCBT_ACTIVATE, hook },
587 { WM_NCACTIVATE, sent|wparam, 0 },
588 { WM_GETICON, sent|optional },
589 { WM_GETICON, sent|optional },
590 { WM_GETICON, sent|optional },
591 { WM_GETTEXT, sent|optional },
592 { WM_ACTIVATE, sent|wparam, 0 },
593 { WM_WINDOWPOSCHANGING, sent|optional },
594 { HCBT_SETFOCUS, hook },
595 { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
596 { WM_SETFOCUS, sent|parent|defwinproc },
597 { HCBT_DESTROYWND, hook },
598 { WM_DESTROY, sent },
599 { WM_NCDESTROY, sent },
602 /* Creation of a modal dialog that is resized inside WM_INITDIALOG (32) */
603 static const struct message WmCreateModalDialogResizeSeq[] = { /* FIXME: add */
604 /* (inside dialog proc, handling WM_INITDIALOG) */
605 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
606 { WM_NCCALCSIZE, sent },
607 { WM_NCACTIVATE, sent|parent|wparam, 0 },
608 { WM_GETTEXT, sent|defwinproc },
609 { WM_ACTIVATE, sent|parent|wparam, 0 },
610 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
611 { WM_WINDOWPOSCHANGING, sent|parent },
612 { WM_NCACTIVATE, sent|wparam, 1 },
613 { WM_ACTIVATE, sent|wparam, 1 },
614 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
615 { WM_SIZE, sent|defwinproc },
616 /* (setting focus) */
617 { WM_SHOWWINDOW, sent|wparam, 1 },
618 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
619 { WM_NCPAINT, sent },
620 { WM_GETTEXT, sent|defwinproc },
621 { WM_ERASEBKGND, sent },
622 { WM_CTLCOLORDLG, sent|defwinproc },
623 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
625 /* (bunch of WM_CTLCOLOR* for each control) */
626 { WM_PAINT, sent|parent },
627 { WM_ENTERIDLE, sent|parent|wparam, 0 },
628 { WM_SETCURSOR, sent|parent },
631 /* SetMenu for NonVisible windows with size change*/
632 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
633 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
634 { WM_NCCALCSIZE, sent|wparam, 1 },
635 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW },
636 { WM_MOVE, sent|defwinproc },
637 { WM_SIZE, sent|defwinproc },
638 { WM_GETICON, sent|optional },
639 { WM_GETICON, sent|optional },
640 { WM_GETICON, sent|optional },
641 { WM_GETTEXT, sent|optional },
642 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
645 /* SetMenu for NonVisible windows with no size change */
646 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
647 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
648 { WM_NCCALCSIZE, sent|wparam, 1 },
649 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
652 /* SetMenu for Visible windows with size change */
653 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
654 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
655 { WM_NCCALCSIZE, sent|wparam, 1 },
656 { WM_NCPAINT, sent|wparam, 1 },
657 { WM_GETTEXT, sent|defwinproc|optional },
658 { WM_ERASEBKGND, sent|optional },
659 { WM_ACTIVATE, sent|optional },
660 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
661 { WM_MOVE, sent|defwinproc },
662 { WM_SIZE, sent|defwinproc },
663 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
664 { WM_NCPAINT, sent|wparam|optional, 1 },
665 { WM_ERASEBKGND, sent|optional },
668 /* SetMenu for Visible windows with no size change */
669 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
670 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
671 { WM_NCCALCSIZE, sent|wparam, 1 },
672 { WM_NCPAINT, sent|wparam, 1 },
673 { WM_GETTEXT, sent|defwinproc|optional },
674 { WM_ERASEBKGND, sent|optional },
675 { WM_ACTIVATE, sent|optional },
676 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
679 /* DrawMenuBar for a visible window */
680 static const struct message WmDrawMenuBarSeq[] =
682 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
683 { WM_NCCALCSIZE, sent|wparam, 1 },
684 { WM_NCPAINT, sent|wparam, 1 },
685 { WM_GETTEXT, sent|defwinproc|optional },
686 { WM_ERASEBKGND, sent|optional },
687 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
691 static const struct message WmSetRedrawFalseSeq[] =
693 { WM_SETREDRAW, sent|wparam, 0 },
697 static const struct message WmSetRedrawTrueSeq[] =
699 { WM_SETREDRAW, sent|wparam, 1 },
703 static const struct message WmEnableWindowSeq[] =
705 { WM_CANCELMODE, sent },
710 static const struct message WmGetScrollRangeSeq[] =
712 { SBM_GETRANGE, sent },
715 static const struct message WmGetScrollInfoSeq[] =
717 { SBM_GETSCROLLINFO, sent },
720 static const struct message WmSetScrollRangeSeq[] =
722 /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
723 sends SBM_SETSCROLLINFO.
725 { SBM_SETSCROLLINFO, sent },
728 /* SetScrollRange for a window without a non-client area */
729 static const struct message WmSetScrollRangeHVSeq[] =
731 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER },
732 { WM_NCCALCSIZE, sent|wparam, 1 },
733 { WM_GETTEXT, sent|defwinproc|optional },
734 { WM_ERASEBKGND, sent|optional },
735 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
738 /* SetScrollRange for a window with a non-client area */
739 static const struct message WmSetScrollRangeHV_NC_Seq[] =
741 { WM_WINDOWPOSCHANGING, sent, /*|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER*/ },
742 { WM_NCCALCSIZE, sent|wparam, 1 },
743 { WM_NCPAINT, sent|optional },
744 { WM_GETTEXT, sent|defwinproc|optional },
745 { WM_GETICON, sent|optional|defwinproc },
746 { WM_GETICON, sent|optional|defwinproc },
747 { WM_GETICON, sent|optional|defwinproc },
748 { WM_GETTEXT, sent|defwinproc|optional },
749 { WM_ERASEBKGND, sent|optional },
750 { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
751 { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|0x1000*/ },
752 { WM_SIZE, sent|defwinproc },
753 { WM_GETTEXT, sent|optional },
754 { WM_GETICON, sent|optional },
755 { WM_GETICON, sent|optional },
756 { WM_GETICON, sent|optional },
757 { WM_GETTEXT, sent|optional },
758 { WM_GETICON, sent|optional },
759 { WM_GETICON, sent|optional },
760 { WM_GETICON, sent|optional },
761 { WM_GETTEXT, sent|optional },
762 { WM_GETICON, sent|optional },
763 { WM_GETICON, sent|optional },
764 { WM_GETICON, sent|optional },
765 { WM_GETTEXT, sent|optional },
769 static int after_end_dialog;
770 static int sequence_cnt, sequence_size;
771 static struct message* sequence;
773 static void add_message(const struct message *msg)
778 sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof (struct message) );
780 if (sequence_cnt == sequence_size)
783 sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof (struct message) );
787 sequence[sequence_cnt].message = msg->message;
788 sequence[sequence_cnt].flags = msg->flags;
789 sequence[sequence_cnt].wParam = msg->wParam;
790 sequence[sequence_cnt].lParam = msg->lParam;
795 static void flush_sequence()
797 HeapFree(GetProcessHeap(), 0, sequence);
799 sequence_cnt = sequence_size = 0;
802 static void ok_sequence(const struct message *expected, const char *context, int todo)
804 static const struct message end_of_sequence = { 0, 0, 0, 0 };
805 const struct message *actual;
807 add_message(&end_of_sequence);
811 while (expected->message && actual->message)
813 trace("expected %04x - actual %04x\n", expected->message, actual->message);
815 if (expected->message == actual->message)
817 if (expected->flags & wparam)
819 if (expected->wParam != actual->wParam && todo)
823 "%s: in msg 0x%04x expecting wParam 0x%x got 0x%x\n",
824 context, expected->message, expected->wParam, actual->wParam);
828 ok (expected->wParam == actual->wParam,
829 "%s: in msg 0x%04x expecting wParam 0x%x got 0x%x\n",
830 context, expected->message, expected->wParam, actual->wParam);
832 if (expected->flags & lparam)
833 ok (expected->lParam == actual->lParam,
834 "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
835 context, expected->message, expected->lParam, actual->lParam);
836 ok ((expected->flags & defwinproc) == (actual->flags & defwinproc),
837 "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
838 context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
839 ok ((expected->flags & beginpaint) == (actual->flags & beginpaint),
840 "%s: the msg 0x%04x should %shave been sent by BeginPaint\n",
841 context, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
842 ok ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
843 "%s: the msg 0x%04x should have been %s\n",
844 context, expected->message, (expected->flags & posted) ? "posted" : "sent");
845 ok ((expected->flags & parent) == (actual->flags & parent),
846 "%s: the msg 0x%04x was expected in %s\n",
847 context, expected->message, (expected->flags & parent) ? "parent" : "child");
848 ok ((expected->flags & hook) == (actual->flags & hook),
849 "%s: the msg 0x%04x should have been sent by a hook\n",
850 context, expected->message);
854 else if (expected->flags & optional)
859 ok (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
860 context, expected->message, actual->message);
867 ok (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
868 context, expected->message, actual->message);
874 /* skip all optional trailing messages */
875 while (expected->message && (expected->flags & optional))
881 if (expected->message || actual->message)
882 ok (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
883 context, expected->message, actual->message);
888 if (expected->message || actual->message)
889 ok (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
890 context, expected->message, actual->message);
896 /******************************** MDI test **********************************/
898 /* CreateWindow for MDI frame window, initially visible */
899 static const struct message WmCreateMDIframeSeq[] = {
900 { HCBT_CREATEWND, hook },
901 { WM_GETMINMAXINFO, sent },
902 { WM_NCCREATE, sent },
903 { WM_NCCALCSIZE, sent|wparam, 0 },
905 { WM_SHOWWINDOW, sent|wparam, 1 },
906 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
907 { HCBT_ACTIVATE, hook },
908 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
909 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
910 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* Win9x */
911 { WM_ACTIVATEAPP, sent|wparam, 1 },
912 { WM_NCACTIVATE, sent|wparam, 1 },
913 { WM_ACTIVATE, sent|wparam, 1 },
914 { HCBT_SETFOCUS, hook },
915 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
916 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
917 /* Win9x adds SWP_NOZORDER below */
918 { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
923 /* DestroyWindow for MDI frame window, initially visible */
924 static const struct message WmDestroyMDIframeSeq[] = {
925 { HCBT_DESTROYWND, hook },
926 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
927 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
928 { WM_NCACTIVATE, sent|wparam, 0 },
929 { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
930 { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
931 { WM_DESTROY, sent },
932 { WM_NCDESTROY, sent },
935 /* CreateWindow for MDI client window, initially visible */
936 static const struct message WmCreateMDIclientSeq[] = {
937 { HCBT_CREATEWND, hook },
938 { WM_NCCREATE, sent },
939 { WM_NCCALCSIZE, sent|wparam, 0 },
943 { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
944 { WM_SHOWWINDOW, sent|wparam, 1 },
945 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE|SWP_NOMOVE },
946 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
949 /* DestroyWindow for MDI client window, initially visible */
950 static const struct message WmDestroyMDIclientSeq[] = {
951 { HCBT_DESTROYWND, hook },
952 { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
953 { WM_SHOWWINDOW, sent|wparam, 0 },
954 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
955 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
956 { WM_DESTROY, sent },
957 { WM_NCDESTROY, sent },
960 /* CreateWindow for MDI child window, initially visible */
961 static const struct message WmCreateMDIchildVisibleSeq[] = {
962 { HCBT_CREATEWND, hook },
963 { WM_NCCREATE, sent },
964 { WM_NCCALCSIZE, sent|wparam, 0 },
968 /* Win2k sends wparam set to
969 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
970 * while Win9x doesn't bother to set child window id according to
971 * CLIENTCREATESTRUCT.idFirstChild
973 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
974 { WM_SHOWWINDOW, sent|wparam, 1 },
975 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
976 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
977 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
978 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
979 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
980 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
982 /* Win9x: message sequence terminates here. */
984 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
985 { HCBT_SETFOCUS, hook }, /* in MDI client */
986 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
987 { WM_SETFOCUS, sent }, /* in MDI client */
988 { HCBT_SETFOCUS, hook },
989 { WM_KILLFOCUS, sent }, /* in MDI client */
990 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
991 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
992 { WM_SETFOCUS, sent|defwinproc },
993 { WM_MDIACTIVATE, sent|defwinproc },
996 /* DestroyWindow for MDI child window, initially visible */
997 static const struct message WmDestroyMDIchildVisibleSeq[] = {
998 { HCBT_DESTROYWND, hook },
999 /* Win2k sends wparam set to
1000 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1001 * while Win9x doesn't bother to set child window id according to
1002 * CLIENTCREATESTRUCT.idFirstChild
1004 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1005 { WM_SHOWWINDOW, sent|wparam, 0 },
1006 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1007 { WM_ERASEBKGND, sent|parent|optional },
1008 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1010 /* { WM_DESTROY, sent }
1011 * Win9x: message sequence terminates here.
1014 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1015 { WM_KILLFOCUS, sent },
1016 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1017 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1018 { WM_SETFOCUS, sent }, /* in MDI client */
1020 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1021 { WM_KILLFOCUS, sent }, /* in MDI client */
1022 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1023 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1024 { WM_SETFOCUS, sent }, /* in MDI client */
1026 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1027 { WM_KILLFOCUS, sent },
1028 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1029 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1030 { WM_SETFOCUS, sent }, /* in MDI client */
1032 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1033 { WM_KILLFOCUS, sent }, /* in MDI client */
1034 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1035 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1036 { WM_SETFOCUS, sent }, /* in MDI client */
1038 { WM_DESTROY, sent },
1040 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1041 { WM_KILLFOCUS, sent },
1042 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1043 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1044 { WM_SETFOCUS, sent }, /* in MDI client */
1046 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1047 { WM_KILLFOCUS, sent }, /* in MDI client */
1048 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1049 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1050 { WM_SETFOCUS, sent }, /* in MDI client */
1052 { WM_NCDESTROY, sent },
1055 /* CreateWindow for MDI child window, initially invisible */
1056 static const struct message WmCreateMDIchildInvisibleSeq[] = {
1057 { HCBT_CREATEWND, hook },
1058 { WM_NCCREATE, sent },
1059 { WM_NCCALCSIZE, sent|wparam, 0 },
1060 { WM_CREATE, sent },
1063 /* Win2k sends wparam set to
1064 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1065 * while Win9x doesn't bother to set child window id according to
1066 * CLIENTCREATESTRUCT.idFirstChild
1068 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1071 /* DestroyWindow for MDI child window, initially invisible */
1072 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
1073 { HCBT_DESTROYWND, hook },
1074 /* Win2k sends wparam set to
1075 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1076 * while Win9x doesn't bother to set child window id according to
1077 * CLIENTCREATESTRUCT.idFirstChild
1079 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1080 { WM_DESTROY, sent },
1081 { WM_NCDESTROY, sent },
1084 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
1085 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
1086 { HCBT_CREATEWND, hook },
1087 { WM_NCCREATE, sent },
1088 { WM_NCCALCSIZE, sent|wparam, 0 },
1089 { WM_CREATE, sent },
1092 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1093 { WM_GETMINMAXINFO, sent },
1094 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
1095 { WM_NCCALCSIZE, sent|wparam, 1 },
1096 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1097 { WM_SIZE, sent|defwinproc },
1099 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1100 { WM_NCCALCSIZE, sent|wparam, 1 },
1101 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1102 /* Win2k sends wparam set to
1103 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1104 * while Win9x doesn't bother to set child window id according to
1105 * CLIENTCREATESTRUCT.idFirstChild
1107 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1108 { WM_SHOWWINDOW, sent|wparam, 1 },
1109 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1110 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1111 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1112 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1113 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1114 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1116 /* Win9x: message sequence terminates here. */
1118 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1119 { HCBT_SETFOCUS, hook }, /* in MDI client */
1120 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1121 { WM_SETFOCUS, sent }, /* in MDI client */
1122 { HCBT_SETFOCUS, hook },
1123 { WM_KILLFOCUS, sent }, /* in MDI client */
1124 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1125 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1126 { WM_SETFOCUS, sent|defwinproc },
1127 { WM_MDIACTIVATE, sent|defwinproc },
1129 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1130 { WM_NCCALCSIZE, sent|wparam, 1 },
1131 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1134 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
1135 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
1136 /* restore the 1st MDI child */
1137 { WM_SETREDRAW, sent|wparam, 0 },
1138 { HCBT_MINMAX, hook },
1139 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
1140 { WM_NCCALCSIZE, sent|wparam, 1 },
1141 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1142 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1143 { WM_SIZE, sent|defwinproc },
1145 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1146 { WM_NCCALCSIZE, sent|wparam, 1 },
1147 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1148 { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
1149 /* create the 2nd MDI child */
1150 { HCBT_CREATEWND, hook },
1151 { WM_NCCREATE, sent },
1152 { WM_NCCALCSIZE, sent|wparam, 0 },
1153 { WM_CREATE, sent },
1156 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1157 { WM_GETMINMAXINFO, sent },
1158 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
1159 { WM_NCCALCSIZE, sent|wparam, 1 },
1160 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1161 { WM_SIZE, sent|defwinproc },
1163 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1164 { WM_NCCALCSIZE, sent|wparam, 1 },
1165 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1166 /* Win2k sends wparam set to
1167 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1168 * while Win9x doesn't bother to set child window id according to
1169 * CLIENTCREATESTRUCT.idFirstChild
1171 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1172 { WM_SHOWWINDOW, sent|wparam, 1 },
1173 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1174 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1175 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1176 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1177 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1179 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
1180 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
1182 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1184 /* Win9x: message sequence terminates here. */
1186 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1187 { HCBT_SETFOCUS, hook },
1188 { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
1189 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
1190 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1191 { WM_SETFOCUS, sent }, /* in MDI client */
1192 { HCBT_SETFOCUS, hook },
1193 { WM_KILLFOCUS, sent }, /* in MDI client */
1194 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1195 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1196 { WM_SETFOCUS, sent|defwinproc },
1198 { WM_MDIACTIVATE, sent|defwinproc },
1200 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1201 { WM_NCCALCSIZE, sent|wparam, 1 },
1202 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1205 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
1206 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
1207 { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
1208 { HCBT_SYSCOMMAND, hook },
1209 { WM_CLOSE, sent|defwinproc },
1210 { WM_MDIDESTROY, sent }, /* in MDI client */
1212 /* bring the 1st MDI child to top */
1213 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
1214 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
1215 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
1216 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
1217 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
1219 /* maximize the 1st MDI child */
1220 { HCBT_MINMAX, hook },
1221 { WM_GETMINMAXINFO, sent|defwinproc },
1222 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|0x8000 },
1223 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
1224 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
1225 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1226 { WM_SIZE, sent|defwinproc },
1228 /* restore the 2nd MDI child */
1229 { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
1230 { HCBT_MINMAX, hook },
1231 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOZORDER|0x8000 },
1232 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
1233 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1234 { WM_SIZE, sent|defwinproc },
1235 { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
1237 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1238 { WM_NCCALCSIZE, sent|wparam, 1 },
1239 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1241 /* bring the 1st MDI child to top */
1242 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1243 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1244 { HCBT_SETFOCUS, hook },
1245 { WM_KILLFOCUS, sent|defwinproc },
1246 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
1247 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1248 { WM_SETFOCUS, sent }, /* in MDI client */
1249 { HCBT_SETFOCUS, hook },
1250 { WM_KILLFOCUS, sent }, /* in MDI client */
1251 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1252 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1253 { WM_SETFOCUS, sent|defwinproc },
1254 { WM_MDIACTIVATE, sent|defwinproc },
1255 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1257 /* apparently ShowWindow(SW_SHOW) on an MDI client */
1258 { WM_SHOWWINDOW, sent|wparam, 1 },
1259 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1260 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1261 { WM_MDIREFRESHMENU, sent },
1263 { HCBT_DESTROYWND, hook },
1264 /* Win2k sends wparam set to
1265 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1266 * while Win9x doesn't bother to set child window id according to
1267 * CLIENTCREATESTRUCT.idFirstChild
1269 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1270 { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
1271 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1272 { WM_ERASEBKGND, sent|parent|optional },
1273 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1275 { WM_DESTROY, sent|defwinproc },
1276 { WM_NCDESTROY, sent|defwinproc },
1279 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
1280 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
1281 { HCBT_MINMAX, hook },
1282 { WM_GETMINMAXINFO, sent },
1283 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
1284 { WM_NCCALCSIZE, sent|wparam, 1 },
1285 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1287 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1288 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1289 { HCBT_SETFOCUS, hook },
1290 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1291 { WM_SETFOCUS, sent }, /* in MDI client */
1292 { HCBT_SETFOCUS, hook },
1293 { WM_KILLFOCUS, sent }, /* in MDI client */
1294 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1295 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1296 { WM_SETFOCUS, sent|defwinproc },
1297 { WM_MDIACTIVATE, sent|defwinproc },
1298 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1299 { WM_SIZE, sent|defwinproc },
1301 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1302 { WM_NCCALCSIZE, sent|wparam, 1 },
1303 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1306 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
1307 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
1308 { HCBT_MINMAX, hook },
1309 { WM_GETMINMAXINFO, sent },
1310 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
1311 { WM_NCCALCSIZE, sent|wparam, 1 },
1312 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1313 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1314 { WM_SIZE, sent|defwinproc },
1316 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1317 { WM_NCCALCSIZE, sent|wparam, 1 },
1318 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1321 /* ShowWindow(SW_RESTORE) for a visible MDI child window */
1322 static const struct message WmRestoreMDIchildVisibleSeq[] = {
1323 { HCBT_MINMAX, hook },
1324 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
1325 { WM_NCCALCSIZE, sent|wparam, 1 },
1326 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1327 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1328 { WM_SIZE, sent|defwinproc },
1330 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1331 { WM_NCCALCSIZE, sent|wparam, 1 },
1332 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1335 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
1336 static const struct message WmRestoreMDIchildInisibleSeq[] = {
1337 { HCBT_MINMAX, hook },
1338 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
1339 { WM_NCCALCSIZE, sent|wparam, 1 },
1340 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1341 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1342 { WM_SIZE, sent|defwinproc },
1344 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1345 { WM_NCCALCSIZE, sent|wparam, 1 },
1346 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1350 static HWND mdi_client;
1351 static WNDPROC old_mdi_client_proc;
1353 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1357 /* do not log painting messages */
1358 if (message != WM_PAINT &&
1359 message != WM_ERASEBKGND &&
1360 message != WM_NCPAINT &&
1361 message != WM_GETTEXT)
1363 trace("mdi client: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1367 case WM_WINDOWPOSCHANGING:
1368 case WM_WINDOWPOSCHANGED:
1370 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
1372 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
1373 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
1374 winpos->hwnd, winpos->hwndInsertAfter,
1375 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
1377 /* Log only documented flags, win2k uses 0x1000 and 0x2000
1378 * in the high word for internal purposes
1380 wParam = winpos->flags & 0xffff;
1385 msg.message = message;
1386 msg.flags = sent|wparam|lparam;
1387 msg.wParam = wParam;
1388 msg.lParam = lParam;
1392 return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
1395 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1397 static long defwndproc_counter = 0;
1401 /* do not log painting messages */
1402 if (message != WM_PAINT &&
1403 message != WM_ERASEBKGND &&
1404 message != WM_NCPAINT &&
1405 message != WM_GETTEXT)
1407 trace("mdi child: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1411 case WM_WINDOWPOSCHANGING:
1412 case WM_WINDOWPOSCHANGED:
1414 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
1416 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
1417 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
1418 winpos->hwnd, winpos->hwndInsertAfter,
1419 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
1421 /* Log only documented flags, win2k uses 0x1000 and 0x2000
1422 * in the high word for internal purposes
1424 wParam = winpos->flags & 0xffff;
1429 msg.message = message;
1430 msg.flags = sent|wparam|lparam;
1431 if (defwndproc_counter) msg.flags |= defwinproc;
1432 msg.wParam = wParam;
1433 msg.lParam = lParam;
1437 defwndproc_counter++;
1438 ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
1439 defwndproc_counter--;
1444 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1446 static long defwndproc_counter = 0;
1450 /* do not log painting messages */
1451 if (message != WM_PAINT &&
1452 message != WM_ERASEBKGND &&
1453 message != WM_NCPAINT &&
1454 message != WM_GETTEXT)
1456 trace("mdi frame: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1460 case WM_WINDOWPOSCHANGING:
1461 case WM_WINDOWPOSCHANGED:
1463 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
1465 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
1466 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
1467 winpos->hwnd, winpos->hwndInsertAfter,
1468 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
1470 /* Log only documented flags, win2k uses 0x1000 and 0x2000
1471 * in the high word for internal purposes
1473 wParam = winpos->flags & 0xffff;
1478 msg.message = message;
1479 msg.flags = sent|wparam|lparam;
1480 if (defwndproc_counter) msg.flags |= defwinproc;
1481 msg.wParam = wParam;
1482 msg.lParam = lParam;
1486 defwndproc_counter++;
1487 ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
1488 defwndproc_counter--;
1493 static BOOL mdi_RegisterWindowClasses(void)
1498 cls.lpfnWndProc = mdi_frame_wnd_proc;
1501 cls.hInstance = GetModuleHandleA(0);
1503 cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
1504 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
1505 cls.lpszMenuName = NULL;
1506 cls.lpszClassName = "MDI_frame_class";
1507 if (!RegisterClassA(&cls)) return FALSE;
1509 cls.lpfnWndProc = mdi_child_wnd_proc;
1510 cls.lpszClassName = "MDI_child_class";
1511 if (!RegisterClassA(&cls)) return FALSE;
1513 if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
1514 old_mdi_client_proc = cls.lpfnWndProc;
1515 cls.hInstance = GetModuleHandleA(0);
1516 cls.lpfnWndProc = mdi_client_hook_proc;
1517 cls.lpszClassName = "MDI_client_class";
1518 if (!RegisterClassA(&cls)) assert(0);
1523 static void test_mdi_messages(void)
1525 MDICREATESTRUCTA mdi_cs;
1526 CLIENTCREATESTRUCT client_cs;
1527 HWND mdi_frame, mdi_child, mdi_child2, active_child;
1530 assert(mdi_RegisterWindowClasses());
1534 trace("creating MDI frame window\n");
1535 mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
1536 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
1537 WS_MAXIMIZEBOX | WS_VISIBLE,
1538 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
1539 GetDesktopWindow(), 0,
1540 GetModuleHandleA(0), NULL);
1542 ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", TRUE);
1544 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1545 ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
1547 trace("creating MDI client window\n");
1548 client_cs.hWindowMenu = 0;
1549 client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
1550 mdi_client = CreateWindowExA(0, "MDI_client_class",
1552 WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
1554 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
1556 ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
1558 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1559 ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
1561 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1562 ok(!active_child, "wrong active MDI child %p\n", active_child);
1563 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
1568 trace("creating visible MDI child window\n");
1569 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
1570 WS_CHILD | WS_VISIBLE,
1571 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
1572 mdi_client, 0, GetModuleHandleA(0), NULL);
1574 ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", TRUE);
1576 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
1577 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
1579 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1580 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
1582 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1583 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
1584 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
1587 DestroyWindow(mdi_child);
1588 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
1590 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1591 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1593 /* Win2k: MDI client still returns a just destroyed child as active
1594 * Win9x: MDI client returns 0
1596 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1597 ok(active_child == mdi_child || /* win2k */
1598 !active_child, /* win9x */
1599 "wrong active MDI child %p\n", active_child);
1600 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
1604 trace("creating invisible MDI child window\n");
1605 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
1607 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
1608 mdi_client, 0, GetModuleHandleA(0), NULL);
1610 ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
1612 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
1613 ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
1615 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1616 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1618 /* Win2k: MDI client still returns a just destroyed child as active
1619 * Win9x: MDI client returns mdi_child2
1621 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1622 ok(active_child == mdi_child || /* win2k */
1623 active_child == mdi_child2, /* win9x */
1624 "wrong active MDI child %p\n", active_child);
1625 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
1628 ShowWindow(mdi_child2, SW_MAXIMIZE);
1629 ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", TRUE);
1631 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
1632 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
1634 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1635 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
1636 ok(zoomed, "wrong zoomed state %d\n", zoomed);
1639 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1640 ok(GetFocus() == mdi_child2 || /* win2k */
1641 GetFocus() == 0, /* win9x */
1642 "wrong focus window %p\n", GetFocus());
1647 ShowWindow(mdi_child2, SW_HIDE);
1648 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
1650 ShowWindow(mdi_child2, SW_RESTORE);
1651 ok_sequence(WmRestoreMDIchildInisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", TRUE);
1654 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
1655 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
1657 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1658 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
1659 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
1665 ShowWindow(mdi_child2, SW_HIDE);
1666 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
1668 ShowWindow(mdi_child2, SW_SHOW);
1669 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", TRUE);
1671 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1672 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1674 ShowWindow(mdi_child2, SW_MAXIMIZE);
1675 ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", TRUE);
1677 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1678 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1680 ShowWindow(mdi_child2, SW_RESTORE);
1681 ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):MDI child", TRUE);
1683 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1684 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1689 ShowWindow(mdi_child2, SW_HIDE);
1690 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
1692 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1693 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1695 DestroyWindow(mdi_child2);
1696 ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", TRUE);
1698 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1699 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1701 /* test for maximized MDI children */
1702 trace("creating maximized visible MDI child window 1\n");
1703 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
1704 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
1705 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
1706 mdi_client, 0, GetModuleHandleA(0), NULL);
1708 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
1709 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
1711 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1712 ok(GetFocus() == mdi_child || /* win2k */
1713 GetFocus() == 0, /* win9x */
1714 "wrong focus window %p\n", GetFocus());
1716 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1717 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
1718 ok(zoomed, "wrong zoomed state %d\n", zoomed);
1721 trace("creating maximized visible MDI child window 2\n");
1722 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
1723 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
1724 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
1725 mdi_client, 0, GetModuleHandleA(0), NULL);
1727 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
1728 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
1729 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
1731 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1732 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
1734 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1735 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
1736 ok(zoomed, "wrong zoomed state %d\n", zoomed);
1739 trace("destroying maximized visible MDI child window 2\n");
1740 DestroyWindow(mdi_child2);
1741 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
1743 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
1745 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1746 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1748 /* Win2k: MDI client still returns a just destroyed child as active
1749 * Win9x: MDI client returns 0
1751 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1752 ok(active_child == mdi_child2 || /* win2k */
1753 !active_child, /* win9x */
1754 "wrong active MDI child %p\n", active_child);
1757 ShowWindow(mdi_child, SW_MAXIMIZE);
1758 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
1761 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1762 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
1764 trace("re-creating maximized visible MDI child window 2\n");
1765 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
1766 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
1767 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
1768 mdi_client, 0, GetModuleHandleA(0), NULL);
1770 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
1771 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
1772 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
1774 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1775 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
1777 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1778 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
1779 ok(zoomed, "wrong zoomed state %d\n", zoomed);
1782 SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
1783 ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
1784 ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
1786 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
1787 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1788 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
1790 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1791 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
1792 ok(zoomed, "wrong zoomed state %d\n", zoomed);
1795 DestroyWindow(mdi_child);
1796 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
1798 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1799 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1801 /* Win2k: MDI client still returns a just destroyed child as active
1802 * Win9x: MDI client returns 0
1804 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1805 ok(active_child == mdi_child || /* win2k */
1806 !active_child, /* win9x */
1807 "wrong active MDI child %p\n", active_child);
1809 /* end of test for maximized MDI children */
1811 mdi_cs.szClass = "MDI_child_Class";
1812 mdi_cs.szTitle = "MDI child";
1813 mdi_cs.hOwner = GetModuleHandleA(0);
1814 mdi_cs.x = CW_USEDEFAULT;
1815 mdi_cs.y = CW_USEDEFAULT;
1816 mdi_cs.cx = CW_USEDEFAULT;
1817 mdi_cs.cy = CW_USEDEFAULT;
1818 mdi_cs.style = WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX;
1820 mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
1821 ok(mdi_child != 0, "MDI child creation failed\n");
1823 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1824 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
1826 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
1827 ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
1828 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1829 ok(!active_child, "wrong active MDI child %p\n", active_child);
1834 DestroyWindow(mdi_client);
1835 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
1837 DestroyWindow(mdi_frame);
1838 ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
1840 /************************* End of MDI test **********************************/
1842 static void test_WM_SETREDRAW(HWND hwnd)
1844 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
1848 SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
1849 ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
1851 ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
1852 ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
1855 SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
1856 ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
1858 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
1859 ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
1861 /* restore original WS_VISIBLE state */
1862 SetWindowLongA(hwnd, GWL_STYLE, style);
1867 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1871 trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1873 msg.message = message;
1874 msg.flags = sent|wparam|lparam;
1875 msg.wParam = wParam;
1876 msg.lParam = lParam;
1879 if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
1880 if (message == WM_TIMER) EndDialog( hwnd, 0 );
1884 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
1886 DWORD style, exstyle;
1889 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
1890 style = GetWindowLongA(hwnd, GWL_STYLE);
1891 /* do not be confused by WS_DLGFRAME set */
1892 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
1894 if (clear) ok(style & clear, "style %08lx should be set\n", clear);
1895 if (set) ok(!(style & set), "style %08lx should not be set\n", set);
1897 ok(SetScrollRange(hwnd, ctl, min, max, FALSE), "SetScrollRange(%d) error %ld\n", ctl, GetLastError());
1898 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
1899 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
1901 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", TRUE);
1903 style = GetWindowLongA(hwnd, GWL_STYLE);
1904 if (set) ok(style & set, "style %08lx should be set\n", set);
1905 if (clear) ok(!(style & clear), "style %08lx should not be set\n", clear);
1907 /* a subsequent call should do nothing */
1908 ok(SetScrollRange(hwnd, ctl, min, max, FALSE), "SetScrollRange(%d) error %ld\n", ctl, GetLastError());
1909 ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
1913 trace("Ignore GetScrollRange error below if you are on Win9x\n");
1914 ok(GetScrollRange(hwnd, ctl, &xmin, &xmax), "GetScrollRange(%d) error %ld\n", ctl, GetLastError());
1915 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT)", FALSE);
1916 ok(xmin == min, "unexpected min scroll value %d\n", xmin);
1917 ok(xmax == max, "unexpected max scroll value %d\n", xmax);
1920 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
1922 DWORD style, exstyle;
1925 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
1926 style = GetWindowLongA(hwnd, GWL_STYLE);
1927 /* do not be confused by WS_DLGFRAME set */
1928 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
1930 if (clear) ok(style & clear, "style %08lx should be set\n", clear);
1931 if (set) ok(!(style & set), "style %08lx should not be set\n", set);
1933 si.cbSize = sizeof(si);
1934 si.fMask = SIF_RANGE;
1937 SetScrollInfo(hwnd, ctl, &si, TRUE);
1938 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
1939 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
1941 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", TRUE);
1943 style = GetWindowLongA(hwnd, GWL_STYLE);
1944 if (set) ok(style & set, "style %08lx should be set\n", set);
1945 if (clear) ok(!(style & clear), "style %08lx should not be set\n", clear);
1947 /* a subsequent call should do nothing */
1948 SetScrollInfo(hwnd, ctl, &si, TRUE);
1949 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
1951 si.fMask = SIF_PAGE;
1953 SetScrollInfo(hwnd, ctl, &si, FALSE);
1954 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
1958 SetScrollInfo(hwnd, ctl, &si, FALSE);
1959 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
1961 si.fMask = SIF_RANGE;
1962 si.nMin = 0xdeadbeef;
1963 si.nMax = 0xdeadbeef;
1964 ok(GetScrollInfo(hwnd, ctl, &si), "GetScrollInfo error %ld\n", GetLastError());
1965 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT)", FALSE);
1966 ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
1967 ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
1970 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
1971 static void test_scroll_messages(HWND hwnd)
1978 ok(GetScrollRange(hwnd, SB_CTL, &min, &max), "GetScrollRange error %ld\n", GetLastError());
1979 if (sequence->message != WmGetScrollRangeSeq[0].message)
1980 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
1981 /* values of min and max are undefined */
1984 ok(SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE), "SetScrollRange error %ld\n", GetLastError());
1985 if (sequence->message != WmSetScrollRangeSeq[0].message)
1986 trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
1991 ok(GetScrollRange(hwnd, SB_CTL, &min, &max), "GetScrollRange error %ld\n", GetLastError());
1992 if (sequence->message != WmGetScrollRangeSeq[0].message)
1993 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
1994 /* values of min and max are undefined */
1997 si.cbSize = sizeof(si);
1998 si.fMask = SIF_RANGE;
2001 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
2002 if (sequence->message != WmSetScrollRangeSeq[0].message)
2003 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
2006 si.fMask = SIF_PAGE;
2008 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
2009 if (sequence->message != WmSetScrollRangeSeq[0].message)
2010 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
2015 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
2016 if (sequence->message != WmSetScrollRangeSeq[0].message)
2017 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
2020 si.fMask = SIF_RANGE;
2021 si.nMin = 0xdeadbeef;
2022 si.nMax = 0xdeadbeef;
2023 ok(GetScrollInfo(hwnd, SB_CTL, &si), "GetScrollInfo error %ld\n", GetLastError());
2024 if (sequence->message != WmGetScrollInfoSeq[0].message)
2025 trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
2026 /* values of min and max are undefined */
2029 /* set WS_HSCROLL */
2030 test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
2031 /* clear WS_HSCROLL */
2032 test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
2034 /* set WS_HSCROLL */
2035 test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
2036 /* clear WS_HSCROLL */
2037 test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
2039 /* set WS_VSCROLL */
2040 test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
2041 /* clear WS_VSCROLL */
2042 test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
2044 /* set WS_VSCROLL */
2045 test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
2046 /* clear WS_VSCROLL */
2047 test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
2050 /* test if we receive the right sequence of messages */
2051 static void test_messages(void)
2053 HWND hwnd, hparent, hchild;
2054 HWND hchild2, hbutton;
2057 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
2058 100, 100, 200, 200, 0, 0, 0, NULL);
2059 ok (hwnd != 0, "Failed to create overlapped window\n");
2060 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
2062 /* test ShowWindow(SW_HIDE) on a newly created invisible window */
2063 ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
2064 ok_sequence(WmHideInvisibleOverlappedSeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
2066 /* test WM_SETREDRAW on a not visible top level window */
2067 test_WM_SETREDRAW(hwnd);
2069 SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
2070 ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
2071 ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
2073 ok(GetActiveWindow() == hwnd, "window should be active\n");
2074 ok(GetFocus() == hwnd, "window should have input focus\n");
2075 ShowWindow(hwnd, SW_HIDE);
2076 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", TRUE);
2078 ShowWindow(hwnd, SW_SHOW);
2079 ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
2081 ok(GetActiveWindow() == hwnd, "window should be active\n");
2082 ok(GetFocus() == hwnd, "window should have input focus\n");
2083 SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
2084 ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", TRUE);
2085 ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
2087 /* test WM_SETREDRAW on a visible top level window */
2088 ShowWindow(hwnd, SW_SHOW);
2089 test_WM_SETREDRAW(hwnd);
2091 trace("testing scroll APIs on a visible top level window %p\n", hwnd);
2092 test_scroll_messages(hwnd);
2094 DestroyWindow(hwnd);
2095 ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
2097 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
2098 100, 100, 200, 200, 0, 0, 0, NULL);
2099 ok (hparent != 0, "Failed to create parent window\n");
2102 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
2103 0, 0, 10, 10, hparent, 0, 0, NULL);
2104 ok (hchild != 0, "Failed to create child window\n");
2105 ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", TRUE);
2106 DestroyWindow(hchild);
2109 /* visible child window with a caption */
2110 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
2111 WS_CHILD | WS_VISIBLE | WS_CAPTION,
2112 0, 0, 10, 10, hparent, 0, 0, NULL);
2113 ok (hchild != 0, "Failed to create child window\n");
2114 ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
2116 trace("testing scroll APIs on a visible child window %p\n", hchild);
2117 test_scroll_messages(hchild);
2119 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
2120 ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
2122 DestroyWindow(hchild);
2125 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
2126 0, 0, 10, 10, hparent, 0, 0, NULL);
2127 ok (hchild != 0, "Failed to create child window\n");
2128 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
2130 hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
2131 100, 100, 50, 50, hparent, 0, 0, NULL);
2132 ok (hchild2 != 0, "Failed to create child2 window\n");
2135 hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
2136 0, 100, 50, 50, hchild, 0, 0, NULL);
2137 ok (hbutton != 0, "Failed to create button window\n");
2139 /* test WM_SETREDRAW on a not visible child window */
2140 test_WM_SETREDRAW(hchild);
2142 ShowWindow(hchild, SW_SHOW);
2143 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
2145 ShowWindow(hchild, SW_HIDE);
2146 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
2148 ShowWindow(hchild, SW_SHOW);
2149 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
2151 /* test WM_SETREDRAW on a visible child window */
2152 test_WM_SETREDRAW(hchild);
2154 MoveWindow(hchild, 10, 10, 20, 20, TRUE);
2155 ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
2157 ShowWindow(hchild, SW_HIDE);
2159 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
2160 ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
2162 ShowWindow(hchild, SW_HIDE);
2164 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
2165 ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
2167 /* DestroyWindow sequence below expects that a child has focus */
2171 DestroyWindow(hchild);
2172 ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
2173 DestroyWindow(hchild2);
2174 DestroyWindow(hbutton);
2177 hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
2178 0, 0, 100, 100, hparent, 0, 0, NULL);
2179 ok (hchild != 0, "Failed to create child popup window\n");
2180 ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
2181 DestroyWindow(hchild);
2183 /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
2185 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
2186 0, 0, 100, 100, hparent, 0, 0, NULL);
2187 ok (hchild != 0, "Failed to create popup window\n");
2188 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
2189 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
2190 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
2192 ShowWindow(hchild, SW_SHOW);
2193 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
2195 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
2196 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
2198 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
2199 ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
2200 DestroyWindow(hchild);
2202 /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
2203 * changes nothing in message sequences.
2206 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
2207 0, 0, 100, 100, hparent, 0, 0, NULL);
2208 ok (hchild != 0, "Failed to create popup window\n");
2209 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
2210 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
2211 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
2213 ShowWindow(hchild, SW_SHOW);
2214 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
2216 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
2217 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
2218 DestroyWindow(hchild);
2221 hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
2222 0, 0, 100, 100, hparent, 0, 0, NULL);
2223 ok(hwnd != 0, "Failed to create custom dialog window\n");
2224 ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
2226 trace("testing scroll APIs on a visible dialog %p\n", hwnd);
2227 test_scroll_messages(hwnd);
2230 after_end_dialog = 1;
2231 EndDialog( hwnd, 0 );
2232 ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
2234 DestroyWindow(hwnd);
2235 after_end_dialog = 0;
2238 DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
2239 ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
2241 /* test showing child with hidden parent */
2242 ShowWindow( hparent, SW_HIDE );
2245 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
2246 0, 0, 10, 10, hparent, 0, 0, NULL);
2247 ok (hchild != 0, "Failed to create child window\n");
2248 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
2250 ShowWindow( hchild, SW_SHOW );
2251 ok_sequence(WmShowChildInvisibleParentSeq, "ShowWindow:show child with invisible parent", TRUE);
2252 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
2253 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
2255 ShowWindow( hchild, SW_HIDE );
2256 ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", TRUE);
2257 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
2258 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
2260 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
2261 ok_sequence(WmShowChildInvisibleParentSeq_2, "SetWindowPos:show child with invisible parent", TRUE);
2262 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
2263 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
2265 SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
2266 ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", TRUE);
2267 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
2268 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
2270 DestroyWindow(hparent);
2273 /* Message sequence for SetMenu */
2274 hmenu = CreateMenu();
2275 ok (hmenu != 0, "Failed to create menu\n");
2276 ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
2277 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
2278 100, 100, 200, 200, 0, hmenu, 0, NULL);
2279 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
2280 ok (SetMenu(hwnd, 0), "SetMenu\n");
2281 ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
2282 ok (SetMenu(hwnd, 0), "SetMenu\n");
2283 ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
2284 ShowWindow(hwnd, SW_SHOW);
2286 ok (SetMenu(hwnd, 0), "SetMenu\n");
2287 ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", TRUE);
2288 ok (SetMenu(hwnd, hmenu), "SetMenu\n");
2289 ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", TRUE);
2291 ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
2292 ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", TRUE);
2294 DestroyWindow(hwnd);
2297 /* Message sequence for EnableWindow */
2298 hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
2299 100, 100, 200, 200, 0, 0, 0, NULL);
2300 ok (hparent != 0, "Failed to create parent window\n");
2301 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
2302 0, 0, 10, 10, hparent, 0, 0, NULL);
2303 ok (hchild != 0, "Failed to create child window\n");
2308 EnableWindow(hparent, FALSE);
2309 ok_sequence(WmEnableWindowSeq, "EnableWindow", FALSE);
2311 DestroyWindow(hparent);
2315 /****************** button message test *************************/
2316 static const struct message WmSetFocusButtonSeq[] =
2318 { HCBT_SETFOCUS, hook },
2319 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2320 { WM_SETFOCUS, sent|wparam, 0 },
2321 { WM_CTLCOLORBTN, sent|defwinproc },
2324 static const struct message WmKillFocusButtonSeq[] =
2326 { HCBT_SETFOCUS, hook },
2327 { WM_KILLFOCUS, sent|wparam, 0 },
2328 { WM_CTLCOLORBTN, sent|defwinproc },
2329 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2332 static const struct message WmSetFocusStaticSeq[] =
2334 { HCBT_SETFOCUS, hook },
2335 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2336 { WM_SETFOCUS, sent|wparam, 0 },
2337 { WM_CTLCOLORSTATIC, sent|defwinproc },
2340 static const struct message WmKillFocusStaticSeq[] =
2342 { HCBT_SETFOCUS, hook },
2343 { WM_KILLFOCUS, sent|wparam, 0 },
2344 { WM_CTLCOLORSTATIC, sent|defwinproc },
2345 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2348 static const struct message WmLButtonDownSeq[] =
2350 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
2351 { HCBT_SETFOCUS, hook },
2352 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2353 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
2354 { WM_CTLCOLORBTN, sent|defwinproc },
2355 { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
2356 { WM_CTLCOLORBTN, sent|defwinproc },
2359 static const struct message WmLButtonUpSeq[] =
2361 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
2362 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
2363 { WM_CTLCOLORBTN, sent|defwinproc },
2364 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
2368 static WNDPROC old_button_proc;
2370 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2372 static long defwndproc_counter = 0;
2376 trace("button: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2378 msg.message = message;
2379 msg.flags = sent|wparam|lparam;
2380 if (defwndproc_counter) msg.flags |= defwinproc;
2381 msg.wParam = wParam;
2382 msg.lParam = lParam;
2385 if (message == BM_SETSTATE)
2386 ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
2388 defwndproc_counter++;
2389 ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
2390 defwndproc_counter--;
2395 static void subclass_button(void)
2399 if (!GetClassInfoA(0, "button", &cls)) assert(0);
2401 old_button_proc = cls.lpfnWndProc;
2403 cls.hInstance = GetModuleHandle(0);
2404 cls.lpfnWndProc = button_hook_proc;
2405 cls.lpszClassName = "my_button_class";
2406 if (!RegisterClassA(&cls)) assert(0);
2409 static void test_button_messages(void)
2414 const struct message *setfocus;
2415 const struct message *killfocus;
2417 { BS_PUSHBUTTON, WmSetFocusButtonSeq, WmKillFocusButtonSeq },
2418 { BS_DEFPUSHBUTTON, WmSetFocusButtonSeq, WmKillFocusButtonSeq },
2419 { BS_CHECKBOX, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2420 { BS_AUTOCHECKBOX, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2421 { BS_RADIOBUTTON, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2422 { BS_3STATE, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2423 { BS_AUTO3STATE, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2424 { BS_GROUPBOX, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2425 { BS_USERBUTTON, WmSetFocusButtonSeq, WmKillFocusButtonSeq },
2426 { BS_AUTORADIOBUTTON, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2427 { BS_OWNERDRAW, WmSetFocusButtonSeq, WmKillFocusButtonSeq }
2434 for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
2436 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP,
2437 0, 0, 50, 14, 0, 0, 0, NULL);
2438 ok(hwnd != 0, "Failed to create button window\n");
2440 ShowWindow(hwnd, SW_SHOW);
2445 trace("button style %08lx\n", button[i].style);
2447 ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
2450 ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
2452 DestroyWindow(hwnd);
2455 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP | WS_VISIBLE,
2456 0, 0, 50, 14, 0, 0, 0, NULL);
2457 ok(hwnd != 0, "Failed to create button window\n");
2462 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
2463 ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
2465 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
2466 ok_sequence(WmLButtonUpSeq, "WM_LBUTTONDOWN on a button", FALSE);
2467 DestroyWindow(hwnd);
2470 /************* painting message test ********************/
2472 static void dump_region(HRGN hrgn)
2475 RGNDATA *data = NULL;
2480 printf( "null region\n" );
2483 if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
2484 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
2485 GetRegionData( hrgn, size, data );
2486 printf("%ld rects:", data->rdh.nCount );
2487 for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
2488 printf( " (%ld,%ld)-(%ld,%ld)", rect->left, rect->top, rect->right, rect->bottom );
2490 HeapFree( GetProcessHeap(), 0, data );
2493 static void check_update_rgn( HWND hwnd, HRGN hrgn )
2497 HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
2498 HRGN update = CreateRectRgn( 0, 0, 0, 0 );
2500 ret = GetUpdateRgn( hwnd, update, FALSE );
2501 ok( ret != ERROR, "GetUpdateRgn failed\n" );
2502 if (ret == NULLREGION)
2504 ok( !hrgn, "Update region shouldn't be empty\n" );
2508 if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
2510 ok( 0, "Regions are different\n" );
2511 if (winetest_debug > 0)
2513 printf( "Update region: " );
2514 dump_region( update );
2515 printf( "Wanted region: " );
2516 dump_region( hrgn );
2520 GetRgnBox( update, &r1 );
2521 GetUpdateRect( hwnd, &r2, FALSE );
2522 ok( r1.left == r2.left && r1.top == r2.top && r1.right == r2.right && r1.bottom == r2.bottom,
2523 "Rectangles are different: %ld,%ld-%ld,%ld / %ld,%ld-%ld,%ld\n",
2524 r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom );
2526 DeleteObject( tmp );
2527 DeleteObject( update );
2530 static const struct message WmInvalidateRgn[] = {
2531 { WM_NCPAINT, sent },
2532 { WM_GETTEXT, sent|defwinproc|optional },
2536 static const struct message WmInvalidateFull[] = {
2537 { WM_NCPAINT, sent|wparam, 1 },
2538 { WM_GETTEXT, sent|defwinproc|optional },
2542 static const struct message WmInvalidateErase[] = {
2543 { WM_NCPAINT, sent|wparam, 1 },
2544 { WM_GETTEXT, sent|defwinproc|optional },
2545 { WM_ERASEBKGND, sent },
2549 static const struct message WmInvalidatePaint[] = {
2551 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
2552 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
2556 static const struct message WmInvalidateErasePaint[] = {
2558 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
2559 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
2560 { WM_ERASEBKGND, sent|beginpaint },
2564 static const struct message WmErase[] = {
2565 { WM_ERASEBKGND, sent },
2569 static const struct message WmPaint[] = {
2574 static void test_paint_messages(void)
2578 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
2579 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
2580 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
2581 100, 100, 200, 200, 0, 0, 0, NULL);
2582 ok (hwnd != 0, "Failed to create overlapped window\n");
2584 ShowWindow( hwnd, SW_SHOW );
2585 UpdateWindow( hwnd );
2586 check_update_rgn( hwnd, 0 );
2587 SetRectRgn( hrgn, 10, 10, 20, 20 );
2588 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
2589 check_update_rgn( hwnd, hrgn );
2590 SetRectRgn( hrgn2, 20, 20, 30, 30 );
2591 RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
2592 CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
2593 check_update_rgn( hwnd, hrgn );
2594 /* validate everything */
2595 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
2596 check_update_rgn( hwnd, 0 );
2597 /* now with frame */
2598 SetRectRgn( hrgn, -5, -5, 20, 20 );
2601 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
2602 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
2604 SetRectRgn( hrgn, 0, 0, 20, 20 ); /* GetUpdateRgn clips to client area */
2605 check_update_rgn( hwnd, hrgn );
2608 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
2609 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
2612 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
2613 ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
2615 GetClientRect( hwnd, &rect );
2616 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
2617 check_update_rgn( hwnd, hrgn );
2620 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
2621 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
2624 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
2625 ok_sequence( WmInvalidatePaint, "InvalidatePaint", TRUE );
2626 check_update_rgn( hwnd, 0 );
2629 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
2630 ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
2631 check_update_rgn( hwnd, 0 );
2634 SetRectRgn( hrgn, 0, 0, 100, 100 );
2635 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
2636 SetRectRgn( hrgn, 0, 0, 50, 100 );
2637 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
2638 SetRectRgn( hrgn, 50, 0, 100, 100 );
2639 check_update_rgn( hwnd, hrgn );
2640 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
2641 ok_sequence( WmEmptySeq, "EmptySeq", FALSE ); /* must not generate messages, everything is valid */
2642 check_update_rgn( hwnd, 0 );
2645 SetRectRgn( hrgn, 0, 0, 100, 100 );
2646 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
2647 SetRectRgn( hrgn, 0, 0, 100, 50 );
2648 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
2649 ok_sequence( WmErase, "Erase", FALSE );
2650 SetRectRgn( hrgn, 0, 50, 100, 100 );
2651 check_update_rgn( hwnd, hrgn );
2654 SetRectRgn( hrgn, 0, 0, 100, 100 );
2655 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
2656 SetRectRgn( hrgn, 0, 0, 50, 50 );
2657 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
2658 ok_sequence( WmPaint, "Paint", FALSE );
2661 SetRectRgn( hrgn, -4, -4, -2, -2 );
2662 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
2663 SetRectRgn( hrgn, -4, -4, -3, -3 );
2664 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
2665 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
2668 SetRectRgn( hrgn, -4, -4, -2, -2 );
2669 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
2670 SetRectRgn( hrgn, -4, -4, -3, -3 );
2671 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
2672 SetRectRgn( hrgn, 0, 0, 1, 1 );
2673 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
2674 ok_sequence( WmPaint, "Paint", TRUE );
2677 SetRectRgn( hrgn, -4, -4, -1, -1 );
2678 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
2679 RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
2680 /* make sure no WM_PAINT was generated */
2681 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
2682 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
2685 SetRectRgn( hrgn, -4, -4, -1, -1 );
2686 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
2687 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
2689 if (msg.hwnd == hwnd && msg.message == WM_PAINT)
2691 /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
2692 INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
2693 ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
2694 ret = GetUpdateRect( hwnd, &rect, FALSE );
2695 ok( ret, "Invalid GetUpdateRect result %d\n", ret );
2696 /* this will send WM_NCPAINT and validate the non client area */
2697 ret = GetUpdateRect( hwnd, &rect, TRUE );
2698 ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
2700 else DispatchMessage( &msg );
2702 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
2704 DeleteObject( hrgn );
2705 DeleteObject( hrgn2 );
2706 DestroyWindow( hwnd );
2715 static DWORD WINAPI thread_proc(void *param)
2718 struct wnd_event *wnd_event = (struct wnd_event *)param;
2720 wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
2721 100, 100, 200, 200, 0, 0, 0, NULL);
2722 ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
2724 SetEvent(wnd_event->event);
2726 while (GetMessage(&msg, 0, 0, 0))
2728 TranslateMessage(&msg);
2729 DispatchMessage(&msg);
2735 static void test_interthread_messages(void)
2742 int len, expected_len;
2743 struct wnd_event wnd_event;
2745 wnd_event.event = CreateEvent(NULL, 0, 0, NULL);
2747 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
2748 ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError());
2750 ok(WaitForSingleObject(wnd_event.event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2752 CloseHandle(wnd_event.event);
2754 SetLastError(0xdeadbeef);
2755 ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeded\n");
2756 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error code %ld\n", GetLastError());
2758 proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
2759 ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %ld\n", GetLastError());
2761 expected_len = lstrlenA("window caption text");
2762 memset(buf, 0, sizeof(buf));
2763 SetLastError(0xdeadbeef);
2764 len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
2765 ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %ld, len %d, expected len %d\n", GetLastError(), len, expected_len);
2766 ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
2768 msg.hwnd = wnd_event.hwnd;
2769 msg.message = WM_GETTEXT;
2770 msg.wParam = sizeof(buf);
2771 msg.lParam = (LPARAM)buf;
2772 memset(buf, 0, sizeof(buf));
2773 SetLastError(0xdeadbeef);
2774 len = DispatchMessageA(&msg);
2775 ok(!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
2776 "DispatchMessageA(WM_GETTEXT) succeded on another thread window: ret %d, error %ld\n", len, GetLastError());
2778 msg.hwnd = wnd_event.hwnd;
2779 msg.message = WM_TIMER;
2781 msg.lParam = GetWindowLongW(wnd_event.hwnd,GWL_WNDPROC);
2782 SetLastError(0xdeadbeef);
2783 len = DispatchMessageA(&msg);
2784 ok(!len && GetLastError() == 0xdeadbeef,
2785 "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %ld\n", len, GetLastError());
2787 ok(PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0), "PostMessageA(WM_QUIT) error %ld\n", GetLastError());
2789 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2790 CloseHandle(hThread);
2793 /************* window procedures ********************/
2795 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2797 static long defwndproc_counter = 0;
2798 static long beginpaint_counter = 0;
2802 trace("%p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2806 case WM_WINDOWPOSCHANGING:
2807 case WM_WINDOWPOSCHANGED:
2809 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
2811 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
2812 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
2813 winpos->hwnd, winpos->hwndInsertAfter,
2814 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
2816 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2817 * in the high word for internal purposes
2819 wParam = winpos->flags & 0xffff;
2824 msg.message = message;
2825 msg.flags = sent|wparam|lparam;
2826 if (defwndproc_counter) msg.flags |= defwinproc;
2827 if (beginpaint_counter) msg.flags |= beginpaint;
2828 msg.wParam = wParam;
2829 msg.lParam = lParam;
2832 if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
2834 HWND parent = GetParent(hwnd);
2836 MINMAXINFO *minmax = (MINMAXINFO *)lParam;
2838 GetClientRect(parent, &rc);
2839 trace("parent %p client size = (%ld x %ld)\n", parent, rc.right, rc.bottom);
2841 trace("ptReserved = (%ld,%ld)\n"
2842 "ptMaxSize = (%ld,%ld)\n"
2843 "ptMaxPosition = (%ld,%ld)\n"
2844 "ptMinTrackSize = (%ld,%ld)\n"
2845 "ptMaxTrackSize = (%ld,%ld)\n",
2846 minmax->ptReserved.x, minmax->ptReserved.y,
2847 minmax->ptMaxSize.x, minmax->ptMaxSize.y,
2848 minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
2849 minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
2850 minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
2852 ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %ld != %ld\n",
2853 minmax->ptMaxSize.x, rc.right);
2854 ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %ld != %ld\n",
2855 minmax->ptMaxSize.y, rc.bottom);
2858 if (message == WM_PAINT)
2861 beginpaint_counter++;
2862 BeginPaint( hwnd, &ps );
2863 beginpaint_counter--;
2864 EndPaint( hwnd, &ps );
2868 defwndproc_counter++;
2869 ret = DefWindowProcA(hwnd, message, wParam, lParam);
2870 defwndproc_counter--;
2875 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2877 static long defwndproc_counter = 0;
2881 trace("popup: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2883 msg.message = message;
2884 msg.flags = sent|wparam|lparam;
2885 if (defwndproc_counter) msg.flags |= defwinproc;
2886 msg.wParam = wParam;
2887 msg.lParam = lParam;
2890 if (message == WM_CREATE)
2892 DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
2893 SetWindowLongA(hwnd, GWL_STYLE, style);
2896 defwndproc_counter++;
2897 ret = DefWindowProcA(hwnd, message, wParam, lParam);
2898 defwndproc_counter--;
2903 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2905 static long defwndproc_counter = 0;
2909 trace("parent: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2911 if (message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
2912 message == WM_SETFOCUS || message == WM_KILLFOCUS ||
2913 message == WM_ENABLE || message == WM_ENTERIDLE ||
2914 message == WM_IME_SETCONTEXT)
2916 msg.message = message;
2917 msg.flags = sent|parent|wparam|lparam;
2918 if (defwndproc_counter) msg.flags |= defwinproc;
2919 msg.wParam = wParam;
2920 msg.lParam = lParam;
2924 defwndproc_counter++;
2925 ret = DefWindowProcA(hwnd, message, wParam, lParam);
2926 defwndproc_counter--;
2931 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2933 static long defwndproc_counter = 0;
2937 trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2939 DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
2940 ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
2941 if (after_end_dialog)
2942 ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
2944 ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
2946 msg.message = message;
2947 msg.flags = sent|wparam|lparam;
2948 if (defwndproc_counter) msg.flags |= defwinproc;
2949 msg.wParam = wParam;
2950 msg.lParam = lParam;
2953 defwndproc_counter++;
2954 ret = DefDlgProcA(hwnd, message, wParam, lParam);
2955 defwndproc_counter--;
2960 static BOOL RegisterWindowClasses(void)
2965 cls.lpfnWndProc = MsgCheckProcA;
2968 cls.hInstance = GetModuleHandleA(0);
2970 cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
2971 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
2972 cls.lpszMenuName = NULL;
2973 cls.lpszClassName = "TestWindowClass";
2974 if(!RegisterClassA(&cls)) return FALSE;
2976 cls.lpfnWndProc = PopupMsgCheckProcA;
2977 cls.lpszClassName = "TestPopupClass";
2978 if(!RegisterClassA(&cls)) return FALSE;
2980 cls.lpfnWndProc = ParentMsgCheckProcA;
2981 cls.lpszClassName = "TestParentClass";
2982 if(!RegisterClassA(&cls)) return FALSE;
2984 cls.lpfnWndProc = DefWindowProcA;
2985 cls.lpszClassName = "SimpleWindowClass";
2986 if(!RegisterClassA(&cls)) return FALSE;
2988 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
2989 cls.lpfnWndProc = TestDlgProcA;
2990 cls.lpszClassName = "TestDialogClass";
2991 if(!RegisterClassA(&cls)) return FALSE;
2996 static HHOOK hCBT_hook;
2998 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
3002 trace("CBT: %d, %08x, %08lx\n", nCode, wParam, lParam);
3004 if (nCode == HCBT_SYSCOMMAND)
3008 msg.message = nCode;
3010 msg.wParam = wParam;
3011 msg.lParam = lParam;
3014 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
3017 /* Log also SetFocus(0) calls */
3018 if (!wParam) wParam = lParam;
3020 if (GetClassNameA((HWND)wParam, buf, sizeof(buf)))
3022 if (!strcmp(buf, "TestWindowClass") ||
3023 !strcmp(buf, "TestParentClass") ||
3024 !strcmp(buf, "TestPopupClass") ||
3025 !strcmp(buf, "SimpleWindowClass") ||
3026 !strcmp(buf, "TestDialogClass") ||
3027 !strcmp(buf, "MDI_frame_class") ||
3028 !strcmp(buf, "MDI_client_class") ||
3029 !strcmp(buf, "MDI_child_class") ||
3030 !strcmp(buf, "my_button_class") ||
3031 !strcmp(buf, "#32770"))
3035 msg.message = nCode;
3037 msg.wParam = wParam;
3038 msg.lParam = lParam;
3042 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
3045 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
3046 static const WCHAR wszAnsi[] = {'U',0};
3048 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
3052 case CB_FINDSTRINGEXACT:
3053 trace("String: %p\n", (LPCWSTR)lParam);
3054 if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
3056 if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
3060 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
3063 static void test_message_conversion(void)
3065 static const WCHAR wszMsgConversionClass[] =
3066 {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
3073 cls.lpfnWndProc = MsgConversionProcW;
3076 cls.hInstance = GetModuleHandleW(NULL);
3078 cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
3079 cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
3080 cls.lpszMenuName = NULL;
3081 cls.lpszClassName = wszMsgConversionClass;
3082 /* this call will fail on Win9x, but that doesn't matter as this test is
3083 * meaningless on those platforms */
3084 if(!RegisterClassW(&cls)) return;
3086 hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
3087 100, 100, 200, 200, 0, 0, 0, NULL);
3088 ok(hwnd != NULL, "Window creation failed\n");
3092 wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
3093 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3094 ok(lRes == 0, "String should have been converted\n");
3095 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3096 ok(lRes == 1, "String shouldn't have been converted\n");
3100 wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
3101 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3102 ok(lRes == 1, "String shouldn't have been converted\n");
3103 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3104 ok(lRes == 1, "String shouldn't have been converted\n");
3106 /* Synchronous messages */
3108 lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3109 ok(lRes == 0, "String should have been converted\n");
3110 lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3111 ok(lRes == 1, "String shouldn't have been converted\n");
3113 /* Asynchronous messages */
3116 lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3117 ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3118 "PostMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3120 lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3121 ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3122 "PostMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3124 lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3125 ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3126 "PosThreadtMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3128 lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3129 ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3130 "PosThreadtMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3132 lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3133 ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3134 "SendNotifyMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3136 lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3137 ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3138 "SendNotifyMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3140 lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
3141 ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3142 "SendMessageCallback on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3144 lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
3145 ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3146 "SendMessageCallback on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3151 if (!RegisterWindowClasses()) assert(0);
3153 hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
3157 test_mdi_messages();
3158 test_button_messages();
3159 test_paint_messages();
3160 test_interthread_messages();
3161 test_message_conversion();
3163 UnhookWindowsHookEx(hCBT_hook);