Correct cases where arguments of ok() calls depend on the order in
[wine/gsoc_dplay.git] / dlls / user / tests / msg.c
blob7ad6bc7178a27814c91b2fc95a5c3b38c21a1d58
1 /*
2 * Unit tests for window message handling
4 * Copyright 1999 Ove Kaaven
5 * Copyright 2003 Dimitrie O. Paun
6 * Copyright 2004 Dmitry Timoshkov
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <assert.h>
24 #include <stdarg.h>
25 #include <stdio.h>
27 #define _WIN32_WINNT 0x0500 /* For WM_CHANGEUISTATE */
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winuser.h"
34 #include "wine/test.h"
36 #define MDI_FIRST_CHILD_ID 2004
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
52 typedef enum {
53 sent=0x1,
54 posted=0x2,
55 parent=0x4,
56 wparam=0x8,
57 lparam=0x10,
58 defwinproc=0x20,
59 beginpaint=0x40,
60 optional=0x80,
61 hook=0x100
62 } msg_flags_t;
64 struct message {
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[] =
74 { 0 }
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 },
82 { WM_CREATE, sent },
83 { 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 },
112 { 0 }
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 },
120 { 0 }
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?
153 { WM_SIZE, sent },
154 { WM_MOVE, sent },
155 #endif
156 { 0 }
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 },
163 { WM_SIZE, sent },
164 { WM_MOVE, sent },
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 },
171 { 0 }
173 /* ShowWindow(SW_HIDE) for an invisible overlapped window */
174 static const struct message WmHideInvisibleOverlappedSeq[] = {
175 { 0 }
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 },
190 { 0 }
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 },
197 { WM_CREATE, sent },
198 { WM_SIZE, sent },
199 { WM_MOVE, sent },
200 { 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 },
209 { WM_CREATE, sent },
210 { WM_STYLECHANGING, sent },
211 { WM_STYLECHANGED, sent },
212 { WM_SIZE, sent },
213 { WM_MOVE, sent },
214 { 0 }
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 },
221 { 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 },
239 { 0 }
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 },
247 { WM_CREATE, sent },
248 { WM_SIZE, sent },
249 { WM_MOVE, sent },
250 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
251 { 0 }
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 },
258 { WM_CREATE, sent },
259 { WM_SIZE, sent },
260 { WM_MOVE, sent },
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 },
268 { 0 }
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 },
276 { WM_CREATE, sent },
277 { WM_SIZE, sent },
278 { WM_MOVE, sent },
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 },
284 { 0 }
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 },
292 { 0 }
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 },
300 { 0 }
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 },
309 { 0 }
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 },
317 { 0 }
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 },
325 { 0 }
327 /* ShowWindow(SW_SHOW) for child with invisible parent */
328 static const struct message WmShowChildInvisibleParentSeq[] = {
329 { WM_SHOWWINDOW, sent|wparam, 1 },
330 { 0 }
332 /* ShowWindow(SW_HIDE) for child with invisible parent */
333 static const struct message WmHideChildInvisibleParentSeq[] = {
334 { WM_SHOWWINDOW, sent|wparam, 0 },
335 { 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 },
341 { 0 }
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 },
347 { 0 }
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 ? */
366 { 0 }
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 },
373 { 0 }
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 },
380 { 0 }
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 },
392 { 0 }
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 },
411 { 0 }
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 },
421 { 0 }
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 },
441 { 0 }
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 },
455 { 0 }
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 },
463 { WM_CREATE, sent },
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 },
505 { WM_SIZE, sent },
506 { WM_MOVE, sent },
507 { 0 }
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 },
532 { 0 }
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 },
578 { WM_TIMER, sent },
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 },
600 { 0 }
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 },
624 { WM_PAINT, sent },
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 },
629 { 0 }
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 },
643 { 0 }
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 },
650 { 0 }
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 },
666 { 0 }
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 },
677 { 0 }
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 },
688 { 0 }
691 static const struct message WmSetRedrawFalseSeq[] =
693 { WM_SETREDRAW, sent|wparam, 0 },
694 { 0 }
697 static const struct message WmSetRedrawTrueSeq[] =
699 { WM_SETREDRAW, sent|wparam, 1 },
700 { 0 }
703 static const struct message WmEnableWindowSeq[] =
705 { WM_CANCELMODE, sent },
706 { WM_ENABLE, sent },
707 { 0 }
710 static const struct message WmGetScrollRangeSeq[] =
712 { SBM_GETRANGE, sent },
713 { 0 }
715 static const struct message WmGetScrollInfoSeq[] =
717 { SBM_GETSCROLLINFO, sent },
718 { 0 }
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 },
726 { 0 }
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 },
736 { 0 }
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 },
766 { 0 }
769 static int after_end_dialog;
770 static int sequence_cnt, sequence_size;
771 static struct message* sequence;
772 static int log_all_parent_messages;
774 static void add_message(const struct message *msg)
776 if (!sequence)
778 sequence_size = 10;
779 sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof (struct message) );
781 if (sequence_cnt == sequence_size)
783 sequence_size *= 2;
784 sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof (struct message) );
786 assert(sequence);
788 sequence[sequence_cnt].message = msg->message;
789 sequence[sequence_cnt].flags = msg->flags;
790 sequence[sequence_cnt].wParam = msg->wParam;
791 sequence[sequence_cnt].lParam = msg->lParam;
793 sequence_cnt++;
796 static void flush_sequence()
798 HeapFree(GetProcessHeap(), 0, sequence);
799 sequence = 0;
800 sequence_cnt = sequence_size = 0;
803 #define ok_sequence( exp, contx, todo) \
804 ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
807 static void ok_sequence_(const struct message *expected, const char *context, int todo,
808 const char *file, int line)
810 static const struct message end_of_sequence = { 0, 0, 0, 0 };
811 const struct message *actual;
812 int failcount = 0;
814 add_message(&end_of_sequence);
816 actual = sequence;
818 while (expected->message && actual->message)
820 trace_( file, line)("expected %04x - actual %04x\n", expected->message, actual->message);
822 if (expected->message == actual->message)
824 if (expected->flags & wparam)
826 if (expected->wParam != actual->wParam && todo)
828 todo_wine {
829 failcount ++;
830 ok_( file, line) (FALSE,
831 "%s: in msg 0x%04x expecting wParam 0x%x got 0x%x\n",
832 context, expected->message, expected->wParam, actual->wParam);
835 else
836 ok_( file, line) (expected->wParam == actual->wParam,
837 "%s: in msg 0x%04x expecting wParam 0x%x got 0x%x\n",
838 context, expected->message, expected->wParam, actual->wParam);
840 if (expected->flags & lparam)
841 ok_( file, line) (expected->lParam == actual->lParam,
842 "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
843 context, expected->message, expected->lParam, actual->lParam);
844 ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
845 "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
846 context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
847 ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
848 "%s: the msg 0x%04x should %shave been sent by BeginPaint\n",
849 context, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
850 ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
851 "%s: the msg 0x%04x should have been %s\n",
852 context, expected->message, (expected->flags & posted) ? "posted" : "sent");
853 ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
854 "%s: the msg 0x%04x was expected in %s\n",
855 context, expected->message, (expected->flags & parent) ? "parent" : "child");
856 ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
857 "%s: the msg 0x%04x should have been sent by a hook\n",
858 context, expected->message);
859 expected++;
860 actual++;
862 else if (expected->flags & optional)
863 expected++;
864 else if (todo)
866 failcount++;
867 todo_wine {
868 ok_( file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
869 context, expected->message, actual->message);
871 flush_sequence();
872 return;
874 else
876 ok_( file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
877 context, expected->message, actual->message);
878 expected++;
879 actual++;
883 /* skip all optional trailing messages */
884 while (expected->message && (expected->flags & optional))
885 expected++;
887 if (todo)
889 todo_wine {
890 if (expected->message || actual->message) {
891 failcount++;
892 ok_( file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
893 context, expected->message, actual->message);
897 else
899 if (expected->message || actual->message)
900 ok_( file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
901 context, expected->message, actual->message);
903 if( todo && !failcount) /* succeeded yet marked todo */
904 todo_wine {
905 ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
908 flush_sequence();
911 /******************************** MDI test **********************************/
913 /* CreateWindow for MDI frame window, initially visible */
914 static const struct message WmCreateMDIframeSeq[] = {
915 { HCBT_CREATEWND, hook },
916 { WM_GETMINMAXINFO, sent },
917 { WM_NCCREATE, sent },
918 { WM_NCCALCSIZE, sent|wparam, 0 },
919 { WM_CREATE, sent },
920 { WM_SHOWWINDOW, sent|wparam, 1 },
921 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
922 { HCBT_ACTIVATE, hook },
923 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
924 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
925 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* Win9x */
926 { WM_ACTIVATEAPP, sent|wparam, 1 },
927 { WM_NCACTIVATE, sent|wparam, 1 },
928 { WM_ACTIVATE, sent|wparam, 1 },
929 { HCBT_SETFOCUS, hook },
930 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
931 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
932 /* Win9x adds SWP_NOZORDER below */
933 { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
934 { WM_SIZE, sent },
935 { WM_MOVE, sent },
936 { 0 }
938 /* DestroyWindow for MDI frame window, initially visible */
939 static const struct message WmDestroyMDIframeSeq[] = {
940 { HCBT_DESTROYWND, hook },
941 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
942 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
943 { WM_NCACTIVATE, sent|wparam, 0 },
944 { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
945 { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
946 { WM_DESTROY, sent },
947 { WM_NCDESTROY, sent },
948 { 0 }
950 /* CreateWindow for MDI client window, initially visible */
951 static const struct message WmCreateMDIclientSeq[] = {
952 { HCBT_CREATEWND, hook },
953 { WM_NCCREATE, sent },
954 { WM_NCCALCSIZE, sent|wparam, 0 },
955 { WM_CREATE, sent },
956 { WM_SIZE, sent },
957 { WM_MOVE, sent },
958 { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
959 { WM_SHOWWINDOW, sent|wparam, 1 },
960 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE|SWP_NOMOVE },
961 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
962 { 0 }
964 /* DestroyWindow for MDI client window, initially visible */
965 static const struct message WmDestroyMDIclientSeq[] = {
966 { HCBT_DESTROYWND, hook },
967 { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
968 { WM_SHOWWINDOW, sent|wparam, 0 },
969 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
970 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
971 { WM_DESTROY, sent },
972 { WM_NCDESTROY, sent },
973 { 0 }
975 /* CreateWindow for MDI child window, initially visible */
976 static const struct message WmCreateMDIchildVisibleSeq[] = {
977 { HCBT_CREATEWND, hook },
978 { WM_NCCREATE, sent },
979 { WM_NCCALCSIZE, sent|wparam, 0 },
980 { WM_CREATE, sent },
981 { WM_SIZE, sent },
982 { WM_MOVE, sent },
983 /* Win2k sends wparam set to
984 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
985 * while Win9x doesn't bother to set child window id according to
986 * CLIENTCREATESTRUCT.idFirstChild
988 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
989 { WM_SHOWWINDOW, sent|wparam, 1 },
990 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
991 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
992 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
993 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
994 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
995 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
997 /* Win9x: message sequence terminates here. */
999 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1000 { HCBT_SETFOCUS, hook }, /* in MDI client */
1001 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1002 { WM_SETFOCUS, sent }, /* in MDI client */
1003 { HCBT_SETFOCUS, hook },
1004 { WM_KILLFOCUS, sent }, /* in MDI client */
1005 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1006 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1007 { WM_SETFOCUS, sent|defwinproc },
1008 { WM_MDIACTIVATE, sent|defwinproc },
1009 { 0 }
1011 /* DestroyWindow for MDI child window, initially visible */
1012 static const struct message WmDestroyMDIchildVisibleSeq[] = {
1013 { HCBT_DESTROYWND, hook },
1014 /* Win2k sends wparam set to
1015 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1016 * while Win9x doesn't bother to set child window id according to
1017 * CLIENTCREATESTRUCT.idFirstChild
1019 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1020 { WM_SHOWWINDOW, sent|wparam, 0 },
1021 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1022 { WM_ERASEBKGND, sent|parent|optional },
1023 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1025 /* { WM_DESTROY, sent }
1026 * Win9x: message sequence terminates here.
1029 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1030 { WM_KILLFOCUS, sent },
1031 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1032 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1033 { WM_SETFOCUS, sent }, /* in MDI client */
1035 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1036 { WM_KILLFOCUS, sent }, /* in MDI client */
1037 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1038 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1039 { WM_SETFOCUS, sent }, /* in MDI client */
1041 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1042 { WM_KILLFOCUS, sent },
1043 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1044 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1045 { WM_SETFOCUS, sent }, /* in MDI client */
1047 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1048 { WM_KILLFOCUS, sent }, /* in MDI client */
1049 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1050 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1051 { WM_SETFOCUS, sent }, /* in MDI client */
1053 { WM_DESTROY, sent },
1055 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1056 { WM_KILLFOCUS, sent },
1057 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1058 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1059 { WM_SETFOCUS, sent }, /* in MDI client */
1061 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1062 { WM_KILLFOCUS, sent }, /* in MDI client */
1063 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1064 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1065 { WM_SETFOCUS, sent }, /* in MDI client */
1067 { WM_NCDESTROY, sent },
1068 { 0 }
1070 /* CreateWindow for MDI child window, initially invisible */
1071 static const struct message WmCreateMDIchildInvisibleSeq[] = {
1072 { HCBT_CREATEWND, hook },
1073 { WM_NCCREATE, sent },
1074 { WM_NCCALCSIZE, sent|wparam, 0 },
1075 { WM_CREATE, sent },
1076 { WM_SIZE, sent },
1077 { WM_MOVE, sent },
1078 /* Win2k sends wparam set to
1079 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1080 * while Win9x doesn't bother to set child window id according to
1081 * CLIENTCREATESTRUCT.idFirstChild
1083 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1084 { 0 }
1086 /* DestroyWindow for MDI child window, initially invisible */
1087 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
1088 { HCBT_DESTROYWND, hook },
1089 /* Win2k sends wparam set to
1090 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1091 * while Win9x doesn't bother to set child window id according to
1092 * CLIENTCREATESTRUCT.idFirstChild
1094 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1095 { WM_DESTROY, sent },
1096 { WM_NCDESTROY, sent },
1097 { 0 }
1099 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
1100 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
1101 { HCBT_CREATEWND, hook },
1102 { WM_NCCREATE, sent },
1103 { WM_NCCALCSIZE, sent|wparam, 0 },
1104 { WM_CREATE, sent },
1105 { WM_SIZE, sent },
1106 { WM_MOVE, sent },
1107 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1108 { WM_GETMINMAXINFO, sent },
1109 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
1110 { WM_NCCALCSIZE, sent|wparam, 1 },
1111 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1112 { WM_SIZE, sent|defwinproc },
1113 /* in MDI frame */
1114 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1115 { WM_NCCALCSIZE, sent|wparam, 1 },
1116 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1117 /* Win2k sends wparam set to
1118 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1119 * while Win9x doesn't bother to set child window id according to
1120 * CLIENTCREATESTRUCT.idFirstChild
1122 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1123 { WM_SHOWWINDOW, sent|wparam, 1 },
1124 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1125 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1126 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1127 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1128 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1129 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1131 /* Win9x: message sequence terminates here. */
1133 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1134 { HCBT_SETFOCUS, hook }, /* in MDI client */
1135 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1136 { WM_SETFOCUS, sent }, /* in MDI client */
1137 { HCBT_SETFOCUS, hook },
1138 { WM_KILLFOCUS, sent }, /* in MDI client */
1139 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1140 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1141 { WM_SETFOCUS, sent|defwinproc },
1142 { WM_MDIACTIVATE, sent|defwinproc },
1143 /* in MDI frame */
1144 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1145 { WM_NCCALCSIZE, sent|wparam, 1 },
1146 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1147 { 0 }
1149 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
1150 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
1151 /* restore the 1st MDI child */
1152 { WM_SETREDRAW, sent|wparam, 0 },
1153 { HCBT_MINMAX, hook },
1154 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
1155 { WM_NCCALCSIZE, sent|wparam, 1 },
1156 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1157 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1158 { WM_SIZE, sent|defwinproc },
1159 /* in MDI frame */
1160 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1161 { WM_NCCALCSIZE, sent|wparam, 1 },
1162 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1163 { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
1164 /* create the 2nd MDI child */
1165 { HCBT_CREATEWND, hook },
1166 { WM_NCCREATE, sent },
1167 { WM_NCCALCSIZE, sent|wparam, 0 },
1168 { WM_CREATE, sent },
1169 { WM_SIZE, sent },
1170 { WM_MOVE, sent },
1171 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1172 { WM_GETMINMAXINFO, sent },
1173 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
1174 { WM_NCCALCSIZE, sent|wparam, 1 },
1175 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1176 { WM_SIZE, sent|defwinproc },
1177 /* in MDI frame */
1178 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1179 { WM_NCCALCSIZE, sent|wparam, 1 },
1180 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1181 /* Win2k sends wparam set to
1182 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1183 * while Win9x doesn't bother to set child window id according to
1184 * CLIENTCREATESTRUCT.idFirstChild
1186 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1187 { WM_SHOWWINDOW, sent|wparam, 1 },
1188 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1189 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1190 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1191 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1192 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1194 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
1195 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
1197 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1199 /* Win9x: message sequence terminates here. */
1201 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1202 { HCBT_SETFOCUS, hook },
1203 { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
1204 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
1205 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1206 { WM_SETFOCUS, sent }, /* in MDI client */
1207 { HCBT_SETFOCUS, hook },
1208 { WM_KILLFOCUS, sent }, /* in MDI client */
1209 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1210 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1211 { WM_SETFOCUS, sent|defwinproc },
1213 { WM_MDIACTIVATE, sent|defwinproc },
1214 /* in MDI frame */
1215 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1216 { WM_NCCALCSIZE, sent|wparam, 1 },
1217 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1218 { 0 }
1220 /* WM_MDICREATE MDI child window, initially visible and maximized */
1221 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
1222 { WM_MDICREATE, sent },
1223 { HCBT_CREATEWND, hook },
1224 { WM_NCCREATE, sent },
1225 { WM_NCCALCSIZE, sent|wparam, 0 },
1226 { WM_CREATE, sent },
1227 { WM_SIZE, sent },
1228 { WM_MOVE, sent },
1229 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1230 { WM_GETMINMAXINFO, sent },
1231 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
1232 { WM_NCCALCSIZE, sent|wparam, 1 },
1233 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1234 { WM_SIZE, sent|defwinproc },
1235 /* in MDI frame */
1236 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1237 { WM_NCCALCSIZE, sent|wparam, 1 },
1238 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1239 /* Win2k sends wparam set to
1240 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1241 * while Win9x doesn't bother to set child window id according to
1242 * CLIENTCREATESTRUCT.idFirstChild
1244 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1245 { WM_SHOWWINDOW, sent|wparam, 1 },
1246 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1247 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1248 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1249 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1250 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1251 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1253 /* Win9x: message sequence terminates here. */
1255 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1256 { HCBT_SETFOCUS, hook }, /* in MDI client */
1257 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1258 { WM_SETFOCUS, sent }, /* in MDI client */
1259 { HCBT_SETFOCUS, hook },
1260 { WM_KILLFOCUS, sent }, /* in MDI client */
1261 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1262 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1263 { WM_SETFOCUS, sent|defwinproc },
1265 { WM_MDIACTIVATE, sent|defwinproc },
1267 /* in MDI child */
1268 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1269 { WM_NCCALCSIZE, sent|wparam, 1 },
1270 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1272 /* in MDI frame */
1273 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1274 { WM_NCCALCSIZE, sent|wparam, 1 },
1275 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1276 { WM_MOVE, sent|defwinproc },
1277 { WM_SIZE, sent|defwinproc },
1279 /* in MDI client */
1280 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
1281 { WM_NCCALCSIZE, sent|wparam, 1 },
1282 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
1283 { WM_SIZE, sent },
1285 /* in MDI child */
1286 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
1287 { WM_NCCALCSIZE, sent|wparam, 1 },
1288 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
1289 { WM_SIZE, sent|defwinproc },
1291 { 0 }
1293 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
1294 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
1295 { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
1296 { HCBT_SYSCOMMAND, hook },
1297 { WM_CLOSE, sent|defwinproc },
1298 { WM_MDIDESTROY, sent }, /* in MDI client */
1300 /* bring the 1st MDI child to top */
1301 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
1302 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
1303 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
1304 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
1305 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
1307 /* maximize the 1st MDI child */
1308 { HCBT_MINMAX, hook },
1309 { WM_GETMINMAXINFO, sent|defwinproc },
1310 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|0x8000 },
1311 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
1312 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
1313 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1314 { WM_SIZE, sent|defwinproc },
1316 /* restore the 2nd MDI child */
1317 { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
1318 { HCBT_MINMAX, hook },
1319 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOZORDER|0x8000 },
1320 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
1321 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1322 { WM_SIZE, sent|defwinproc },
1323 { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
1324 /* in MDI frame */
1325 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1326 { WM_NCCALCSIZE, sent|wparam, 1 },
1327 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1329 /* bring the 1st MDI child to top */
1330 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1331 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1332 { HCBT_SETFOCUS, hook },
1333 { WM_KILLFOCUS, sent|defwinproc },
1334 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
1335 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1336 { WM_SETFOCUS, sent }, /* in MDI client */
1337 { HCBT_SETFOCUS, hook },
1338 { WM_KILLFOCUS, sent }, /* in MDI client */
1339 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1340 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1341 { WM_SETFOCUS, sent|defwinproc },
1342 { WM_MDIACTIVATE, sent|defwinproc },
1343 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1345 /* apparently ShowWindow(SW_SHOW) on an MDI client */
1346 { WM_SHOWWINDOW, sent|wparam, 1 },
1347 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1348 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1349 { WM_MDIREFRESHMENU, sent },
1351 { HCBT_DESTROYWND, hook },
1352 /* Win2k sends wparam set to
1353 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1354 * while Win9x doesn't bother to set child window id according to
1355 * CLIENTCREATESTRUCT.idFirstChild
1357 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1358 { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
1359 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1360 { WM_ERASEBKGND, sent|parent|optional },
1361 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1363 { WM_DESTROY, sent|defwinproc },
1364 { WM_NCDESTROY, sent|defwinproc },
1365 { 0 }
1367 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
1368 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
1369 { WM_MDIDESTROY, sent }, /* in MDI client */
1370 { WM_SHOWWINDOW, sent|wparam, 0 },
1371 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1372 { WM_ERASEBKGND, sent|parent|optional },
1373 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1375 { HCBT_SETFOCUS, hook },
1376 { WM_KILLFOCUS, sent },
1377 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1378 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1379 { WM_SETFOCUS, sent }, /* in MDI client */
1380 { HCBT_SETFOCUS, hook },
1381 { WM_KILLFOCUS, sent }, /* in MDI client */
1382 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1383 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1384 { WM_SETFOCUS, sent },
1386 /* in MDI child */
1387 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1388 { WM_NCCALCSIZE, sent|wparam, 1 },
1389 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1391 /* in MDI frame */
1392 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1393 { WM_NCCALCSIZE, sent|wparam, 1 },
1394 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1395 { WM_MOVE, sent|defwinproc },
1396 { WM_SIZE, sent|defwinproc },
1398 /* in MDI client */
1399 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
1400 { WM_NCCALCSIZE, sent|wparam, 1 },
1401 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
1402 { WM_SIZE, sent },
1404 /* in MDI child */
1405 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
1406 { WM_NCCALCSIZE, sent|wparam, 1 },
1407 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
1408 { WM_SIZE, sent|defwinproc },
1410 /* in MDI child */
1411 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1412 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
1413 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1415 /* in MDI frame */
1416 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1417 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
1418 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1419 { WM_MOVE, sent|defwinproc },
1420 { WM_SIZE, sent|defwinproc },
1422 /* in MDI client */
1423 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
1424 { WM_NCCALCSIZE, sent|wparam, 1 },
1425 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
1426 { WM_SIZE, sent },
1428 /* in MDI child */
1429 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOZORDER },
1430 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
1431 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
1432 { WM_SIZE, sent|defwinproc },
1434 /* in MDI frame */
1435 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1436 { WM_NCCALCSIZE, sent|wparam, 1 },
1437 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1439 { WM_NCACTIVATE, sent|wparam, 0 },
1440 { WM_MDIACTIVATE, sent },
1442 { HCBT_MINMAX, hook },
1443 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|0x8000 },
1444 { WM_NCCALCSIZE, sent|wparam, 1 },
1445 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1446 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE|0x8000 },
1447 { WM_SIZE, sent|defwinproc },
1449 /* in MDI child */
1450 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1451 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
1452 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1454 /* in MDI frame */
1455 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1456 { WM_NCCALCSIZE, sent|wparam, 1 },
1457 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1458 { WM_MOVE, sent|defwinproc },
1459 { WM_SIZE, sent|defwinproc },
1461 /* in MDI client */
1462 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
1463 { WM_NCCALCSIZE, sent|wparam, 1 },
1464 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
1465 { WM_SIZE, sent },
1467 { HCBT_SETFOCUS, hook },
1468 { WM_KILLFOCUS, sent },
1469 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1470 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1471 { WM_SETFOCUS, sent }, /* in MDI client */
1473 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
1475 { HCBT_DESTROYWND, hook },
1476 /* Win2k sends wparam set to
1477 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1478 * while Win9x doesn't bother to set child window id according to
1479 * CLIENTCREATESTRUCT.idFirstChild
1481 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1483 { WM_SHOWWINDOW, sent|wparam, 0 },
1484 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1485 { WM_ERASEBKGND, sent|parent|optional },
1486 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1488 { WM_DESTROY, sent },
1489 { WM_NCDESTROY, sent },
1490 { 0 }
1492 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
1493 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
1494 { HCBT_MINMAX, hook },
1495 { WM_GETMINMAXINFO, sent },
1496 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
1497 { WM_NCCALCSIZE, sent|wparam, 1 },
1498 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1500 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1501 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1502 { HCBT_SETFOCUS, hook },
1503 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1504 { WM_SETFOCUS, sent }, /* in MDI client */
1505 { HCBT_SETFOCUS, hook },
1506 { WM_KILLFOCUS, sent }, /* in MDI client */
1507 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1508 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1509 { WM_SETFOCUS, sent|defwinproc },
1510 { WM_MDIACTIVATE, sent|defwinproc },
1511 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1512 { WM_SIZE, sent|defwinproc },
1513 /* in MDI frame */
1514 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1515 { WM_NCCALCSIZE, sent|wparam, 1 },
1516 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1517 { 0 }
1519 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
1520 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
1521 { HCBT_MINMAX, hook },
1522 { WM_GETMINMAXINFO, sent },
1523 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
1524 { WM_NCCALCSIZE, sent|wparam, 1 },
1525 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1526 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1527 { WM_SIZE, sent|defwinproc },
1528 /* in MDI frame */
1529 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1530 { WM_NCCALCSIZE, sent|wparam, 1 },
1531 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1532 { 0 }
1534 /* ShowWindow(SW_RESTORE) for a visible MDI child window */
1535 static const struct message WmRestoreMDIchildVisibleSeq[] = {
1536 { HCBT_MINMAX, hook },
1537 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
1538 { WM_NCCALCSIZE, sent|wparam, 1 },
1539 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1540 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1541 { WM_SIZE, sent|defwinproc },
1542 /* in MDI frame */
1543 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1544 { WM_NCCALCSIZE, sent|wparam, 1 },
1545 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1546 { 0 }
1548 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
1549 static const struct message WmRestoreMDIchildInisibleSeq[] = {
1550 { HCBT_MINMAX, hook },
1551 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
1552 { WM_NCCALCSIZE, sent|wparam, 1 },
1553 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1554 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1555 { WM_SIZE, sent|defwinproc },
1556 /* in MDI frame */
1557 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1558 { WM_NCCALCSIZE, sent|wparam, 1 },
1559 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1560 { 0 }
1563 static HWND mdi_client;
1564 static WNDPROC old_mdi_client_proc;
1566 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1568 struct message msg;
1570 /* do not log painting messages */
1571 if (message != WM_PAINT &&
1572 message != WM_ERASEBKGND &&
1573 message != WM_NCPAINT &&
1574 message != WM_GETTEXT &&
1575 message != WM_MDIGETACTIVE)
1577 trace("mdi client: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1579 switch (message)
1581 case WM_WINDOWPOSCHANGING:
1582 case WM_WINDOWPOSCHANGED:
1584 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
1586 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
1587 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
1588 winpos->hwnd, winpos->hwndInsertAfter,
1589 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
1591 /* Log only documented flags, win2k uses 0x1000 and 0x2000
1592 * in the high word for internal purposes
1594 wParam = winpos->flags & 0xffff;
1595 break;
1599 msg.message = message;
1600 msg.flags = sent|wparam|lparam;
1601 msg.wParam = wParam;
1602 msg.lParam = lParam;
1603 add_message(&msg);
1606 return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
1609 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1611 static long defwndproc_counter = 0;
1612 LRESULT ret;
1613 struct message msg;
1615 /* do not log painting messages */
1616 if (message != WM_PAINT &&
1617 message != WM_ERASEBKGND &&
1618 message != WM_NCPAINT &&
1619 message != WM_GETTEXT)
1621 trace("mdi child: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1623 switch (message)
1625 case WM_WINDOWPOSCHANGING:
1626 case WM_WINDOWPOSCHANGED:
1628 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
1630 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
1631 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
1632 winpos->hwnd, winpos->hwndInsertAfter,
1633 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
1635 /* Log only documented flags, win2k uses 0x1000 and 0x2000
1636 * in the high word for internal purposes
1638 wParam = winpos->flags & 0xffff;
1639 break;
1642 case WM_MDIACTIVATE:
1644 HWND active, client = GetParent(hwnd);
1646 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
1648 if (hwnd == (HWND)lParam) /* if we are being activated */
1649 ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
1650 else
1651 ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
1652 break;
1656 msg.message = message;
1657 msg.flags = sent|wparam|lparam;
1658 if (defwndproc_counter) msg.flags |= defwinproc;
1659 msg.wParam = wParam;
1660 msg.lParam = lParam;
1661 add_message(&msg);
1664 defwndproc_counter++;
1665 ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
1666 defwndproc_counter--;
1668 return ret;
1671 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1673 static long defwndproc_counter = 0;
1674 LRESULT ret;
1675 struct message msg;
1677 /* do not log painting messages */
1678 if (message != WM_PAINT &&
1679 message != WM_ERASEBKGND &&
1680 message != WM_NCPAINT &&
1681 message != WM_GETTEXT)
1683 trace("mdi frame: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1685 switch (message)
1687 case WM_WINDOWPOSCHANGING:
1688 case WM_WINDOWPOSCHANGED:
1690 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
1692 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
1693 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
1694 winpos->hwnd, winpos->hwndInsertAfter,
1695 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
1697 /* Log only documented flags, win2k uses 0x1000 and 0x2000
1698 * in the high word for internal purposes
1700 wParam = winpos->flags & 0xffff;
1701 break;
1705 msg.message = message;
1706 msg.flags = sent|wparam|lparam;
1707 if (defwndproc_counter) msg.flags |= defwinproc;
1708 msg.wParam = wParam;
1709 msg.lParam = lParam;
1710 add_message(&msg);
1713 defwndproc_counter++;
1714 ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
1715 defwndproc_counter--;
1717 return ret;
1720 static BOOL mdi_RegisterWindowClasses(void)
1722 WNDCLASSA cls;
1724 cls.style = 0;
1725 cls.lpfnWndProc = mdi_frame_wnd_proc;
1726 cls.cbClsExtra = 0;
1727 cls.cbWndExtra = 0;
1728 cls.hInstance = GetModuleHandleA(0);
1729 cls.hIcon = 0;
1730 cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
1731 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
1732 cls.lpszMenuName = NULL;
1733 cls.lpszClassName = "MDI_frame_class";
1734 if (!RegisterClassA(&cls)) return FALSE;
1736 cls.lpfnWndProc = mdi_child_wnd_proc;
1737 cls.lpszClassName = "MDI_child_class";
1738 if (!RegisterClassA(&cls)) return FALSE;
1740 if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
1741 old_mdi_client_proc = cls.lpfnWndProc;
1742 cls.hInstance = GetModuleHandleA(0);
1743 cls.lpfnWndProc = mdi_client_hook_proc;
1744 cls.lpszClassName = "MDI_client_class";
1745 if (!RegisterClassA(&cls)) assert(0);
1747 return TRUE;
1750 static void test_mdi_messages(void)
1752 MDICREATESTRUCTA mdi_cs;
1753 CLIENTCREATESTRUCT client_cs;
1754 HWND mdi_frame, mdi_child, mdi_child2, active_child;
1755 BOOL zoomed;
1756 HMENU hMenu = CreateMenu();
1758 assert(mdi_RegisterWindowClasses());
1760 flush_sequence();
1762 trace("creating MDI frame window\n");
1763 mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
1764 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
1765 WS_MAXIMIZEBOX | WS_VISIBLE,
1766 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
1767 GetDesktopWindow(), hMenu,
1768 GetModuleHandleA(0), NULL);
1769 assert(mdi_frame);
1770 ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", TRUE);
1772 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1773 ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
1775 trace("creating MDI client window\n");
1776 client_cs.hWindowMenu = 0;
1777 client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
1778 mdi_client = CreateWindowExA(0, "MDI_client_class",
1779 NULL,
1780 WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
1781 0, 0, 0, 0,
1782 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
1783 assert(mdi_client);
1784 ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
1786 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1787 ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
1789 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1790 ok(!active_child, "wrong active MDI child %p\n", active_child);
1791 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
1793 SetFocus(0);
1794 flush_sequence();
1796 trace("creating invisible MDI child window\n");
1797 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
1798 WS_CHILD,
1799 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
1800 mdi_client, 0, GetModuleHandleA(0), NULL);
1801 assert(mdi_child);
1803 flush_sequence();
1804 ShowWindow(mdi_child, SW_SHOWNORMAL);
1805 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
1807 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
1808 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
1810 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1811 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1813 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1814 ok(!active_child, "wrong active MDI child %p\n", active_child);
1815 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
1817 ShowWindow(mdi_child, SW_HIDE);
1818 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
1819 flush_sequence();
1821 ShowWindow(mdi_child, SW_SHOW);
1822 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
1824 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
1825 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
1827 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1828 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1830 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1831 ok(!active_child, "wrong active MDI child %p\n", active_child);
1832 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
1834 DestroyWindow(mdi_child);
1835 flush_sequence();
1837 trace("creating visible MDI child window\n");
1838 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
1839 WS_CHILD | WS_VISIBLE,
1840 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
1841 mdi_client, 0, GetModuleHandleA(0), NULL);
1842 assert(mdi_child);
1843 ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", TRUE);
1845 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
1846 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
1848 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1849 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
1851 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1852 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
1853 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
1854 flush_sequence();
1856 DestroyWindow(mdi_child);
1857 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
1859 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1860 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1862 /* Win2k: MDI client still returns a just destroyed child as active
1863 * Win9x: MDI client returns 0
1865 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1866 ok(active_child == mdi_child || /* win2k */
1867 !active_child, /* win9x */
1868 "wrong active MDI child %p\n", active_child);
1869 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
1871 flush_sequence();
1873 trace("creating invisible MDI child window\n");
1874 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
1875 WS_CHILD,
1876 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
1877 mdi_client, 0, GetModuleHandleA(0), NULL);
1878 assert(mdi_child2);
1879 ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
1881 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
1882 ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
1884 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1885 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1887 /* Win2k: MDI client still returns a just destroyed child as active
1888 * Win9x: MDI client returns mdi_child2
1890 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1891 ok(active_child == mdi_child || /* win2k */
1892 active_child == mdi_child2, /* win9x */
1893 "wrong active MDI child %p\n", active_child);
1894 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
1895 flush_sequence();
1897 ShowWindow(mdi_child2, SW_MAXIMIZE);
1898 ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", TRUE);
1900 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
1901 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
1903 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1904 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
1905 ok(zoomed, "wrong zoomed state %d\n", zoomed);
1906 flush_sequence();
1908 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1909 ok(GetFocus() == mdi_child2 || /* win2k */
1910 GetFocus() == 0, /* win9x */
1911 "wrong focus window %p\n", GetFocus());
1913 SetFocus(0);
1914 flush_sequence();
1916 ShowWindow(mdi_child2, SW_HIDE);
1917 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
1919 ShowWindow(mdi_child2, SW_RESTORE);
1920 ok_sequence(WmRestoreMDIchildInisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", TRUE);
1921 flush_sequence();
1923 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
1924 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
1926 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1927 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
1928 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
1929 flush_sequence();
1931 SetFocus(0);
1932 flush_sequence();
1934 ShowWindow(mdi_child2, SW_HIDE);
1935 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
1937 ShowWindow(mdi_child2, SW_SHOW);
1938 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
1940 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1941 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1943 ShowWindow(mdi_child2, SW_MAXIMIZE);
1944 ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", TRUE);
1946 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1947 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1949 ShowWindow(mdi_child2, SW_RESTORE);
1950 ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):MDI child", TRUE);
1952 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1953 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1955 SetFocus(0);
1956 flush_sequence();
1958 ShowWindow(mdi_child2, SW_HIDE);
1959 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
1961 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1962 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1964 DestroyWindow(mdi_child2);
1965 ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
1967 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1968 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1970 /* test for maximized MDI children */
1971 trace("creating maximized visible MDI child window 1\n");
1972 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
1973 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
1974 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
1975 mdi_client, 0, GetModuleHandleA(0), NULL);
1976 assert(mdi_child);
1977 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
1978 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
1980 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1981 ok(GetFocus() == mdi_child || /* win2k */
1982 GetFocus() == 0, /* win9x */
1983 "wrong focus window %p\n", GetFocus());
1985 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1986 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
1987 ok(zoomed, "wrong zoomed state %d\n", zoomed);
1988 flush_sequence();
1990 trace("creating maximized visible MDI child window 2\n");
1991 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
1992 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
1993 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
1994 mdi_client, 0, GetModuleHandleA(0), NULL);
1995 assert(mdi_child2);
1996 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
1997 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
1998 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
2000 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2001 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
2003 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2004 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
2005 ok(zoomed, "wrong zoomed state %d\n", zoomed);
2006 flush_sequence();
2008 trace("destroying maximized visible MDI child window 2\n");
2009 DestroyWindow(mdi_child2);
2010 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
2012 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
2014 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2015 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2017 /* Win2k: MDI client still returns a just destroyed child as active
2018 * Win9x: MDI client returns 0
2020 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2021 ok(active_child == mdi_child2 || /* win2k */
2022 !active_child, /* win9x */
2023 "wrong active MDI child %p\n", active_child);
2024 flush_sequence();
2026 ShowWindow(mdi_child, SW_MAXIMIZE);
2027 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
2028 flush_sequence();
2030 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2031 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
2033 trace("re-creating maximized visible MDI child window 2\n");
2034 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
2035 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
2036 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
2037 mdi_client, 0, GetModuleHandleA(0), NULL);
2038 assert(mdi_child2);
2039 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
2040 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
2041 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
2043 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2044 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
2046 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2047 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
2048 ok(zoomed, "wrong zoomed state %d\n", zoomed);
2049 flush_sequence();
2051 SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
2052 ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
2053 ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
2055 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
2056 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2057 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
2059 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2060 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
2061 ok(zoomed, "wrong zoomed state %d\n", zoomed);
2062 flush_sequence();
2064 DestroyWindow(mdi_child);
2065 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
2067 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2068 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2070 /* Win2k: MDI client still returns a just destroyed child as active
2071 * Win9x: MDI client returns 0
2073 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2074 ok(active_child == mdi_child || /* win2k */
2075 !active_child, /* win9x */
2076 "wrong active MDI child %p\n", active_child);
2077 flush_sequence();
2078 /* end of test for maximized MDI children */
2080 mdi_cs.szClass = "MDI_child_Class";
2081 mdi_cs.szTitle = "MDI child";
2082 mdi_cs.hOwner = GetModuleHandleA(0);
2083 mdi_cs.x = 0;
2084 mdi_cs.y = 0;
2085 mdi_cs.cx = CW_USEDEFAULT;
2086 mdi_cs.cy = CW_USEDEFAULT;
2087 mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
2088 mdi_cs.lParam = 0;
2089 mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
2090 ok(mdi_child != 0, "MDI child creation failed\n");
2091 ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
2093 ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
2095 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2096 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
2098 ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
2099 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2100 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
2102 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2103 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
2104 ok(zoomed, "wrong zoomed state %d\n", zoomed);
2105 flush_sequence();
2107 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
2108 ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
2110 ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
2111 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2112 ok(!active_child, "wrong active MDI child %p\n", active_child);
2114 SetFocus(0);
2115 flush_sequence();
2117 DestroyWindow(mdi_client);
2118 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
2120 DestroyWindow(mdi_frame);
2121 ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
2123 /************************* End of MDI test **********************************/
2125 static void test_WM_SETREDRAW(HWND hwnd)
2127 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
2129 flush_sequence();
2131 SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
2132 ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
2134 ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
2135 ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
2137 flush_sequence();
2138 SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
2139 ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
2141 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
2142 ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
2144 /* restore original WS_VISIBLE state */
2145 SetWindowLongA(hwnd, GWL_STYLE, style);
2147 flush_sequence();
2150 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2152 struct message msg;
2154 trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2156 msg.message = message;
2157 msg.flags = sent|wparam|lparam;
2158 msg.wParam = wParam;
2159 msg.lParam = lParam;
2160 add_message(&msg);
2162 if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
2163 if (message == WM_TIMER) EndDialog( hwnd, 0 );
2164 return 0;
2167 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
2169 DWORD style, exstyle;
2170 INT xmin, xmax;
2171 BOOL ret;
2173 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
2174 style = GetWindowLongA(hwnd, GWL_STYLE);
2175 /* do not be confused by WS_DLGFRAME set */
2176 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
2178 if (clear) ok(style & clear, "style %08lx should be set\n", clear);
2179 if (set) ok(!(style & set), "style %08lx should not be set\n", set);
2181 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
2182 ok( ret, "SetScrollRange(%d) error %ld\n", ctl, GetLastError());
2183 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
2184 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
2185 else
2186 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
2188 style = GetWindowLongA(hwnd, GWL_STYLE);
2189 if (set) ok(style & set, "style %08lx should be set\n", set);
2190 if (clear) ok(!(style & clear), "style %08lx should not be set\n", clear);
2192 /* a subsequent call should do nothing */
2193 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
2194 ok( ret, "SetScrollRange(%d) error %ld\n", ctl, GetLastError());
2195 ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
2197 xmin = 0xdeadbeef;
2198 xmax = 0xdeadbeef;
2199 trace("Ignore GetScrollRange error below if you are on Win9x\n");
2200 ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
2201 ok( ret, "GetScrollRange(%d) error %ld\n", ctl, GetLastError());
2202 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT)", FALSE);
2203 ok(xmin == min, "unexpected min scroll value %d\n", xmin);
2204 ok(xmax == max, "unexpected max scroll value %d\n", xmax);
2207 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
2209 DWORD style, exstyle;
2210 SCROLLINFO si;
2211 BOOL ret;
2213 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
2214 style = GetWindowLongA(hwnd, GWL_STYLE);
2215 /* do not be confused by WS_DLGFRAME set */
2216 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
2218 if (clear) ok(style & clear, "style %08lx should be set\n", clear);
2219 if (set) ok(!(style & set), "style %08lx should not be set\n", set);
2221 si.cbSize = sizeof(si);
2222 si.fMask = SIF_RANGE;
2223 si.nMin = min;
2224 si.nMax = max;
2225 SetScrollInfo(hwnd, ctl, &si, TRUE);
2226 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
2227 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
2228 else
2229 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
2231 style = GetWindowLongA(hwnd, GWL_STYLE);
2232 if (set) ok(style & set, "style %08lx should be set\n", set);
2233 if (clear) ok(!(style & clear), "style %08lx should not be set\n", clear);
2235 /* a subsequent call should do nothing */
2236 SetScrollInfo(hwnd, ctl, &si, TRUE);
2237 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
2239 si.fMask = SIF_PAGE;
2240 si.nPage = 5;
2241 SetScrollInfo(hwnd, ctl, &si, FALSE);
2242 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
2244 si.fMask = SIF_POS;
2245 si.nPos = max - 1;
2246 SetScrollInfo(hwnd, ctl, &si, FALSE);
2247 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
2249 si.fMask = SIF_RANGE;
2250 si.nMin = 0xdeadbeef;
2251 si.nMax = 0xdeadbeef;
2252 ret = GetScrollInfo(hwnd, ctl, &si);
2253 ok( ret, "GetScrollInfo error %ld\n", GetLastError());
2254 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT)", FALSE);
2255 ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
2256 ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
2259 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
2260 static void test_scroll_messages(HWND hwnd)
2262 SCROLLINFO si;
2263 INT min, max;
2264 BOOL ret;
2266 min = 0xdeadbeef;
2267 max = 0xdeadbeef;
2268 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
2269 ok( ret, "GetScrollRange error %ld\n", GetLastError());
2270 if (sequence->message != WmGetScrollRangeSeq[0].message)
2271 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
2272 /* values of min and max are undefined */
2273 flush_sequence();
2275 ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
2276 ok( ret, "SetScrollRange error %ld\n", GetLastError());
2277 if (sequence->message != WmSetScrollRangeSeq[0].message)
2278 trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
2279 flush_sequence();
2281 min = 0xdeadbeef;
2282 max = 0xdeadbeef;
2283 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
2284 ok( ret, "GetScrollRange error %ld\n", GetLastError());
2285 if (sequence->message != WmGetScrollRangeSeq[0].message)
2286 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
2287 /* values of min and max are undefined */
2288 flush_sequence();
2290 si.cbSize = sizeof(si);
2291 si.fMask = SIF_RANGE;
2292 si.nMin = 20;
2293 si.nMax = 160;
2294 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
2295 if (sequence->message != WmSetScrollRangeSeq[0].message)
2296 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
2297 flush_sequence();
2299 si.fMask = SIF_PAGE;
2300 si.nPage = 10;
2301 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
2302 if (sequence->message != WmSetScrollRangeSeq[0].message)
2303 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
2304 flush_sequence();
2306 si.fMask = SIF_POS;
2307 si.nPos = 20;
2308 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
2309 if (sequence->message != WmSetScrollRangeSeq[0].message)
2310 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
2311 flush_sequence();
2313 si.fMask = SIF_RANGE;
2314 si.nMin = 0xdeadbeef;
2315 si.nMax = 0xdeadbeef;
2316 ret = GetScrollInfo(hwnd, SB_CTL, &si);
2317 ok( ret, "GetScrollInfo error %ld\n", GetLastError());
2318 if (sequence->message != WmGetScrollInfoSeq[0].message)
2319 trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
2320 /* values of min and max are undefined */
2321 flush_sequence();
2323 /* set WS_HSCROLL */
2324 test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
2325 /* clear WS_HSCROLL */
2326 test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
2328 /* set WS_HSCROLL */
2329 test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
2330 /* clear WS_HSCROLL */
2331 test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
2333 /* set WS_VSCROLL */
2334 test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
2335 /* clear WS_VSCROLL */
2336 test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
2338 /* set WS_VSCROLL */
2339 test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
2340 /* clear WS_VSCROLL */
2341 test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
2344 /* test if we receive the right sequence of messages */
2345 static void test_messages(void)
2347 HWND hwnd, hparent, hchild;
2348 HWND hchild2, hbutton;
2349 HMENU hmenu;
2350 MSG msg;
2352 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
2353 100, 100, 200, 200, 0, 0, 0, NULL);
2354 ok (hwnd != 0, "Failed to create overlapped window\n");
2355 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
2357 /* test ShowWindow(SW_HIDE) on a newly created invisible window */
2358 ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
2359 ok_sequence(WmHideInvisibleOverlappedSeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
2361 /* test WM_SETREDRAW on a not visible top level window */
2362 test_WM_SETREDRAW(hwnd);
2364 SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
2365 ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
2366 ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
2368 ok(GetActiveWindow() == hwnd, "window should be active\n");
2369 ok(GetFocus() == hwnd, "window should have input focus\n");
2370 ShowWindow(hwnd, SW_HIDE);
2371 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", TRUE);
2373 ShowWindow(hwnd, SW_SHOW);
2374 ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
2376 ok(GetActiveWindow() == hwnd, "window should be active\n");
2377 ok(GetFocus() == hwnd, "window should have input focus\n");
2378 SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
2379 ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
2380 ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
2382 /* test WM_SETREDRAW on a visible top level window */
2383 ShowWindow(hwnd, SW_SHOW);
2384 test_WM_SETREDRAW(hwnd);
2386 trace("testing scroll APIs on a visible top level window %p\n", hwnd);
2387 test_scroll_messages(hwnd);
2389 DestroyWindow(hwnd);
2390 ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
2392 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
2393 100, 100, 200, 200, 0, 0, 0, NULL);
2394 ok (hparent != 0, "Failed to create parent window\n");
2395 flush_sequence();
2397 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
2398 0, 0, 10, 10, hparent, 0, 0, NULL);
2399 ok (hchild != 0, "Failed to create child window\n");
2400 ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", TRUE);
2401 DestroyWindow(hchild);
2402 flush_sequence();
2404 /* visible child window with a caption */
2405 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
2406 WS_CHILD | WS_VISIBLE | WS_CAPTION,
2407 0, 0, 10, 10, hparent, 0, 0, NULL);
2408 ok (hchild != 0, "Failed to create child window\n");
2409 ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
2411 trace("testing scroll APIs on a visible child window %p\n", hchild);
2412 test_scroll_messages(hchild);
2414 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
2415 ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
2417 DestroyWindow(hchild);
2418 flush_sequence();
2420 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
2421 0, 0, 10, 10, hparent, 0, 0, NULL);
2422 ok (hchild != 0, "Failed to create child window\n");
2423 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
2425 hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
2426 100, 100, 50, 50, hparent, 0, 0, NULL);
2427 ok (hchild2 != 0, "Failed to create child2 window\n");
2428 flush_sequence();
2430 hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
2431 0, 100, 50, 50, hchild, 0, 0, NULL);
2432 ok (hbutton != 0, "Failed to create button window\n");
2434 /* test WM_SETREDRAW on a not visible child window */
2435 test_WM_SETREDRAW(hchild);
2437 ShowWindow(hchild, SW_SHOW);
2438 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
2440 ShowWindow(hchild, SW_HIDE);
2441 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
2443 ShowWindow(hchild, SW_SHOW);
2444 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
2446 /* test WM_SETREDRAW on a visible child window */
2447 test_WM_SETREDRAW(hchild);
2449 MoveWindow(hchild, 10, 10, 20, 20, TRUE);
2450 ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
2452 ShowWindow(hchild, SW_HIDE);
2453 flush_sequence();
2454 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
2455 ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
2457 ShowWindow(hchild, SW_HIDE);
2458 flush_sequence();
2459 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
2460 ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
2462 /* DestroyWindow sequence below expects that a child has focus */
2463 SetFocus(hchild);
2464 flush_sequence();
2466 DestroyWindow(hchild);
2467 ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
2468 DestroyWindow(hchild2);
2469 DestroyWindow(hbutton);
2471 flush_sequence();
2472 hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
2473 0, 0, 100, 100, hparent, 0, 0, NULL);
2474 ok (hchild != 0, "Failed to create child popup window\n");
2475 ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
2476 DestroyWindow(hchild);
2478 /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
2479 flush_sequence();
2480 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
2481 0, 0, 100, 100, hparent, 0, 0, NULL);
2482 ok (hchild != 0, "Failed to create popup window\n");
2483 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
2484 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
2485 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
2486 flush_sequence();
2487 ShowWindow(hchild, SW_SHOW);
2488 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
2489 flush_sequence();
2490 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
2491 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
2492 flush_sequence();
2493 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
2494 ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
2495 DestroyWindow(hchild);
2497 /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
2498 * changes nothing in message sequences.
2500 flush_sequence();
2501 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
2502 0, 0, 100, 100, hparent, 0, 0, NULL);
2503 ok (hchild != 0, "Failed to create popup window\n");
2504 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
2505 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
2506 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
2507 flush_sequence();
2508 ShowWindow(hchild, SW_SHOW);
2509 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
2510 flush_sequence();
2511 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
2512 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
2513 DestroyWindow(hchild);
2515 flush_sequence();
2516 hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
2517 0, 0, 100, 100, hparent, 0, 0, NULL);
2518 ok(hwnd != 0, "Failed to create custom dialog window\n");
2519 ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
2521 trace("testing scroll APIs on a visible dialog %p\n", hwnd);
2522 test_scroll_messages(hwnd);
2524 flush_sequence();
2525 after_end_dialog = 1;
2526 EndDialog( hwnd, 0 );
2527 ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
2529 DestroyWindow(hwnd);
2530 after_end_dialog = 0;
2532 flush_sequence();
2533 DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
2534 ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
2536 /* test showing child with hidden parent */
2537 ShowWindow( hparent, SW_HIDE );
2538 flush_sequence();
2540 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
2541 0, 0, 10, 10, hparent, 0, 0, NULL);
2542 ok (hchild != 0, "Failed to create child window\n");
2543 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
2545 ShowWindow( hchild, SW_SHOW );
2546 ok_sequence(WmShowChildInvisibleParentSeq, "ShowWindow:show child with invisible parent", TRUE);
2547 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
2548 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
2550 ShowWindow( hchild, SW_HIDE );
2551 ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", TRUE);
2552 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
2553 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
2555 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
2556 ok_sequence(WmShowChildInvisibleParentSeq_2, "SetWindowPos:show child with invisible parent", TRUE);
2557 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
2558 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
2560 SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
2561 ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", TRUE);
2562 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
2563 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
2565 DestroyWindow(hchild);
2566 DestroyWindow(hparent);
2567 flush_sequence();
2569 /* Message sequence for SetMenu */
2570 ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a window without a menu\n");
2571 ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
2573 hmenu = CreateMenu();
2574 ok (hmenu != 0, "Failed to create menu\n");
2575 ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
2576 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
2577 100, 100, 200, 200, 0, hmenu, 0, NULL);
2578 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
2579 ok (SetMenu(hwnd, 0), "SetMenu\n");
2580 ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
2581 ok (SetMenu(hwnd, 0), "SetMenu\n");
2582 ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
2583 ShowWindow(hwnd, SW_SHOW);
2584 flush_sequence();
2585 ok (SetMenu(hwnd, 0), "SetMenu\n");
2586 ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", TRUE);
2587 ok (SetMenu(hwnd, hmenu), "SetMenu\n");
2588 ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", TRUE);
2590 ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
2591 ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", TRUE);
2593 DestroyWindow(hwnd);
2594 flush_sequence();
2596 /* Message sequence for EnableWindow */
2597 hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
2598 100, 100, 200, 200, 0, 0, 0, NULL);
2599 ok (hparent != 0, "Failed to create parent window\n");
2600 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
2601 0, 0, 10, 10, hparent, 0, 0, NULL);
2602 ok (hchild != 0, "Failed to create child window\n");
2604 SetFocus(hchild);
2605 flush_sequence();
2607 EnableWindow(hparent, FALSE);
2608 ok_sequence(WmEnableWindowSeq, "EnableWindow", FALSE);
2610 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
2611 flush_sequence();
2612 PostMessage( hparent, WM_USER, 0, 0 );
2613 PostMessage( hparent, WM_USER+1, 0, 0 );
2614 /* PeekMessage(NULL) fails, but still removes the message */
2615 SetLastError(0xdeadbeef);
2616 ok( !PeekMessage( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
2617 ok( GetLastError() == ERROR_NOACCESS, "last error is %ld\n", GetLastError() );
2618 ok( PeekMessage( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
2619 ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
2621 DestroyWindow(hchild);
2622 DestroyWindow(hparent);
2623 flush_sequence();
2626 /****************** button message test *************************/
2627 static const struct message WmSetFocusButtonSeq[] =
2629 { HCBT_SETFOCUS, hook },
2630 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2631 { WM_SETFOCUS, sent|wparam, 0 },
2632 { WM_CTLCOLORBTN, sent|defwinproc },
2633 { 0 }
2635 static const struct message WmKillFocusButtonSeq[] =
2637 { HCBT_SETFOCUS, hook },
2638 { WM_KILLFOCUS, sent|wparam, 0 },
2639 { WM_CTLCOLORBTN, sent|defwinproc },
2640 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2641 { 0 }
2643 static const struct message WmSetFocusStaticSeq[] =
2645 { HCBT_SETFOCUS, hook },
2646 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2647 { WM_SETFOCUS, sent|wparam, 0 },
2648 { WM_CTLCOLORSTATIC, sent|defwinproc },
2649 { 0 }
2651 static const struct message WmKillFocusStaticSeq[] =
2653 { HCBT_SETFOCUS, hook },
2654 { WM_KILLFOCUS, sent|wparam, 0 },
2655 { WM_CTLCOLORSTATIC, sent|defwinproc },
2656 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2657 { 0 }
2659 static const struct message WmLButtonDownSeq[] =
2661 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
2662 { HCBT_SETFOCUS, hook },
2663 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2664 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
2665 { WM_CTLCOLORBTN, sent|defwinproc },
2666 { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
2667 { WM_CTLCOLORBTN, sent|defwinproc },
2668 { 0 }
2670 static const struct message WmLButtonUpSeq[] =
2672 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
2673 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
2674 { WM_CTLCOLORBTN, sent|defwinproc },
2675 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
2676 { 0 }
2679 static WNDPROC old_button_proc;
2681 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2683 static long defwndproc_counter = 0;
2684 LRESULT ret;
2685 struct message msg;
2687 trace("button: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2689 msg.message = message;
2690 msg.flags = sent|wparam|lparam;
2691 if (defwndproc_counter) msg.flags |= defwinproc;
2692 msg.wParam = wParam;
2693 msg.lParam = lParam;
2694 add_message(&msg);
2696 if (message == BM_SETSTATE)
2697 ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
2699 defwndproc_counter++;
2700 ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
2701 defwndproc_counter--;
2703 return ret;
2706 static void subclass_button(void)
2708 WNDCLASSA cls;
2710 if (!GetClassInfoA(0, "button", &cls)) assert(0);
2712 old_button_proc = cls.lpfnWndProc;
2714 cls.hInstance = GetModuleHandle(0);
2715 cls.lpfnWndProc = button_hook_proc;
2716 cls.lpszClassName = "my_button_class";
2717 if (!RegisterClassA(&cls)) assert(0);
2720 static void test_button_messages(void)
2722 static const struct
2724 DWORD style;
2725 DWORD dlg_code;
2726 const struct message *setfocus;
2727 const struct message *killfocus;
2728 } button[] = {
2729 { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
2730 WmSetFocusButtonSeq, WmKillFocusButtonSeq },
2731 { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
2732 WmSetFocusButtonSeq, WmKillFocusButtonSeq },
2733 { BS_CHECKBOX, DLGC_BUTTON,
2734 WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2735 { BS_AUTOCHECKBOX, DLGC_BUTTON,
2736 WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2737 { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
2738 WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2739 { BS_3STATE, DLGC_BUTTON,
2740 WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2741 { BS_AUTO3STATE, DLGC_BUTTON,
2742 WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2743 { BS_GROUPBOX, DLGC_STATIC,
2744 WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2745 { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
2746 WmSetFocusButtonSeq, WmKillFocusButtonSeq },
2747 { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
2748 WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2749 { BS_OWNERDRAW, DLGC_BUTTON,
2750 WmSetFocusButtonSeq, WmKillFocusButtonSeq }
2752 unsigned int i;
2753 HWND hwnd;
2754 DWORD dlg_code;
2756 subclass_button();
2758 for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
2760 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP,
2761 0, 0, 50, 14, 0, 0, 0, NULL);
2762 ok(hwnd != 0, "Failed to create button window\n");
2764 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
2765 ok(dlg_code == button[i].dlg_code, "%d: wrong dlg_code %08lx\n", i, dlg_code);
2767 ShowWindow(hwnd, SW_SHOW);
2768 UpdateWindow(hwnd);
2769 SetFocus(0);
2770 flush_sequence();
2772 trace("button style %08lx\n", button[i].style);
2773 SetFocus(hwnd);
2774 ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
2776 SetFocus(0);
2777 ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
2779 DestroyWindow(hwnd);
2782 hwnd = CreateWindowExA(0, "my_button_class", "test", BS_PUSHBUTTON | WS_POPUP | WS_VISIBLE,
2783 0, 0, 50, 14, 0, 0, 0, NULL);
2784 ok(hwnd != 0, "Failed to create button window\n");
2786 SetFocus(0);
2787 flush_sequence();
2789 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
2790 ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
2792 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
2793 ok_sequence(WmLButtonUpSeq, "WM_LBUTTONDOWN on a button", FALSE);
2794 DestroyWindow(hwnd);
2797 /************* painting message test ********************/
2799 static void dump_region(HRGN hrgn)
2801 DWORD i, size;
2802 RGNDATA *data = NULL;
2803 RECT *rect;
2805 if (!hrgn)
2807 printf( "null region\n" );
2808 return;
2810 if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
2811 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
2812 GetRegionData( hrgn, size, data );
2813 printf("%ld rects:", data->rdh.nCount );
2814 for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
2815 printf( " (%ld,%ld)-(%ld,%ld)", rect->left, rect->top, rect->right, rect->bottom );
2816 printf("\n");
2817 HeapFree( GetProcessHeap(), 0, data );
2820 static void check_update_rgn( HWND hwnd, HRGN hrgn )
2822 INT ret;
2823 RECT r1, r2;
2824 HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
2825 HRGN update = CreateRectRgn( 0, 0, 0, 0 );
2827 ret = GetUpdateRgn( hwnd, update, FALSE );
2828 ok( ret != ERROR, "GetUpdateRgn failed\n" );
2829 if (ret == NULLREGION)
2831 ok( !hrgn, "Update region shouldn't be empty\n" );
2833 else
2835 if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
2837 ok( 0, "Regions are different\n" );
2838 if (winetest_debug > 0)
2840 printf( "Update region: " );
2841 dump_region( update );
2842 printf( "Wanted region: " );
2843 dump_region( hrgn );
2847 GetRgnBox( update, &r1 );
2848 GetUpdateRect( hwnd, &r2, FALSE );
2849 ok( r1.left == r2.left && r1.top == r2.top && r1.right == r2.right && r1.bottom == r2.bottom,
2850 "Rectangles are different: %ld,%ld-%ld,%ld / %ld,%ld-%ld,%ld\n",
2851 r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom );
2853 DeleteObject( tmp );
2854 DeleteObject( update );
2857 static const struct message WmInvalidateRgn[] = {
2858 { WM_NCPAINT, sent },
2859 { WM_GETTEXT, sent|defwinproc|optional },
2860 { 0 }
2863 static const struct message WmGetUpdateRect[] = {
2864 { WM_NCPAINT, sent },
2865 { WM_GETTEXT, sent|defwinproc|optional },
2866 { WM_PAINT, sent },
2867 { 0 }
2870 static const struct message WmInvalidateFull[] = {
2871 { WM_NCPAINT, sent|wparam, 1 },
2872 { WM_GETTEXT, sent|defwinproc|optional },
2873 { 0 }
2876 static const struct message WmInvalidateErase[] = {
2877 { WM_NCPAINT, sent|wparam, 1 },
2878 { WM_GETTEXT, sent|defwinproc|optional },
2879 { WM_ERASEBKGND, sent },
2880 { 0 }
2883 static const struct message WmInvalidatePaint[] = {
2884 { WM_PAINT, sent },
2885 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
2886 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
2887 { 0 }
2890 static const struct message WmInvalidateErasePaint[] = {
2891 { WM_PAINT, sent },
2892 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
2893 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
2894 { WM_ERASEBKGND, sent|beginpaint },
2895 { 0 }
2898 static const struct message WmInvalidateErasePaint2[] = {
2899 { WM_PAINT, sent },
2900 { WM_NCPAINT, sent|beginpaint },
2901 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
2902 { WM_ERASEBKGND, sent|beginpaint },
2903 { 0 }
2906 static const struct message WmErase[] = {
2907 { WM_ERASEBKGND, sent },
2908 { 0 }
2911 static const struct message WmPaint[] = {
2912 { WM_PAINT, sent },
2913 { 0 }
2916 static const struct message WmParentOnlyPaint[] = {
2917 { WM_PAINT, sent|parent },
2918 { 0 }
2921 static const struct message WmInvalidateParent[] = {
2922 { WM_NCPAINT, sent|parent },
2923 { WM_GETTEXT, sent|defwinproc|parent|optional },
2924 { WM_ERASEBKGND, sent|parent },
2925 { 0 }
2928 static const struct message WmInvalidateParentChild[] = {
2929 { WM_NCPAINT, sent|parent },
2930 { WM_GETTEXT, sent|defwinproc|parent|optional },
2931 { WM_ERASEBKGND, sent|parent },
2932 { WM_NCPAINT, sent },
2933 { WM_GETTEXT, sent|defwinproc|optional },
2934 { WM_ERASEBKGND, sent },
2935 { 0 }
2938 static const struct message WmInvalidateParentChild2[] = {
2939 { WM_ERASEBKGND, sent|parent },
2940 { WM_NCPAINT, sent },
2941 { WM_GETTEXT, sent|defwinproc|optional },
2942 { WM_ERASEBKGND, sent },
2943 { 0 }
2946 static const struct message WmParentPaint[] = {
2947 { WM_PAINT, sent|parent },
2948 { WM_PAINT, sent },
2949 { 0 }
2952 static const struct message WmParentPaintNc[] = {
2953 { WM_PAINT, sent|parent },
2954 { WM_PAINT, sent },
2955 { WM_NCPAINT, sent|beginpaint },
2956 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
2957 { WM_ERASEBKGND, sent|beginpaint },
2958 { 0 }
2961 static const struct message WmChildPaintNc[] = {
2962 { WM_PAINT, sent },
2963 { WM_NCPAINT, sent|beginpaint },
2964 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
2965 { WM_ERASEBKGND, sent|beginpaint },
2966 { 0 }
2969 static const struct message WmParentErasePaint[] = {
2970 { WM_PAINT, sent|parent },
2971 { WM_NCPAINT, sent|parent|beginpaint },
2972 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
2973 { WM_ERASEBKGND, sent|parent|beginpaint },
2974 { WM_PAINT, sent },
2975 { WM_NCPAINT, sent|beginpaint },
2976 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
2977 { WM_ERASEBKGND, sent|beginpaint },
2978 { 0 }
2981 static const struct message WmParentOnlyNcPaint[] = {
2982 { WM_PAINT, sent|parent },
2983 { WM_NCPAINT, sent|parent|beginpaint },
2984 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
2985 { 0 }
2988 static const struct message WmSetParentStyle[] = {
2989 { WM_STYLECHANGING, sent|parent },
2990 { WM_STYLECHANGED, sent|parent },
2991 { 0 }
2994 static void test_paint_messages(void)
2996 RECT rect;
2997 POINT pt;
2998 MSG msg;
2999 HWND hparent, hchild;
3000 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
3001 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
3002 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
3003 100, 100, 200, 200, 0, 0, 0, NULL);
3004 ok (hwnd != 0, "Failed to create overlapped window\n");
3006 ShowWindow( hwnd, SW_SHOW );
3007 UpdateWindow( hwnd );
3009 /* try to flush pending X expose events */
3010 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
3011 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3013 check_update_rgn( hwnd, 0 );
3014 SetRectRgn( hrgn, 10, 10, 20, 20 );
3015 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
3016 check_update_rgn( hwnd, hrgn );
3017 SetRectRgn( hrgn2, 20, 20, 30, 30 );
3018 RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
3019 CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
3020 check_update_rgn( hwnd, hrgn );
3021 /* validate everything */
3022 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
3023 check_update_rgn( hwnd, 0 );
3024 /* now with frame */
3025 SetRectRgn( hrgn, -5, -5, 20, 20 );
3027 /* flush pending messages */
3028 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3030 flush_sequence();
3031 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
3032 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
3034 SetRectRgn( hrgn, 0, 0, 20, 20 ); /* GetUpdateRgn clips to client area */
3035 check_update_rgn( hwnd, hrgn );
3037 flush_sequence();
3038 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
3039 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
3041 flush_sequence();
3042 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
3043 ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
3045 GetClientRect( hwnd, &rect );
3046 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
3047 check_update_rgn( hwnd, hrgn );
3049 flush_sequence();
3050 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
3051 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
3053 flush_sequence();
3054 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
3055 ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
3056 check_update_rgn( hwnd, 0 );
3058 flush_sequence();
3059 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
3060 ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
3061 check_update_rgn( hwnd, 0 );
3063 flush_sequence();
3064 SetRectRgn( hrgn, 0, 0, 100, 100 );
3065 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
3066 SetRectRgn( hrgn, 0, 0, 50, 100 );
3067 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
3068 SetRectRgn( hrgn, 50, 0, 100, 100 );
3069 check_update_rgn( hwnd, hrgn );
3070 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
3071 ok_sequence( WmEmptySeq, "EmptySeq", FALSE ); /* must not generate messages, everything is valid */
3072 check_update_rgn( hwnd, 0 );
3074 flush_sequence();
3075 SetRectRgn( hrgn, 0, 0, 100, 100 );
3076 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
3077 SetRectRgn( hrgn, 0, 0, 100, 50 );
3078 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
3079 ok_sequence( WmErase, "Erase", FALSE );
3080 SetRectRgn( hrgn, 0, 50, 100, 100 );
3081 check_update_rgn( hwnd, hrgn );
3083 flush_sequence();
3084 SetRectRgn( hrgn, 0, 0, 100, 100 );
3085 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
3086 SetRectRgn( hrgn, 0, 0, 50, 50 );
3087 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
3088 ok_sequence( WmPaint, "Paint", FALSE );
3090 flush_sequence();
3091 SetRectRgn( hrgn, -4, -4, -2, -2 );
3092 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
3093 SetRectRgn( hrgn, -200, -200, -198, -198 );
3094 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
3095 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
3097 flush_sequence();
3098 SetRectRgn( hrgn, -4, -4, -2, -2 );
3099 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
3100 SetRectRgn( hrgn, -4, -4, -3, -3 );
3101 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
3102 SetRectRgn( hrgn, 0, 0, 1, 1 );
3103 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
3104 ok_sequence( WmPaint, "Paint", FALSE );
3106 flush_sequence();
3107 SetRectRgn( hrgn, -4, -4, -1, -1 );
3108 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
3109 RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
3110 /* make sure no WM_PAINT was generated */
3111 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3112 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
3114 flush_sequence();
3115 SetRectRgn( hrgn, -4, -4, -1, -1 );
3116 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
3117 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
3119 if (msg.hwnd == hwnd && msg.message == WM_PAINT)
3121 /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
3122 INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
3123 ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
3124 ret = GetUpdateRect( hwnd, &rect, FALSE );
3125 ok( ret, "Invalid GetUpdateRect result %d\n", ret );
3126 /* this will send WM_NCPAINT and validate the non client area */
3127 ret = GetUpdateRect( hwnd, &rect, TRUE );
3128 ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
3130 DispatchMessage( &msg );
3132 ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
3134 DestroyWindow( hwnd );
3136 /* now test with a child window */
3138 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
3139 100, 100, 200, 200, 0, 0, 0, NULL);
3140 ok (hparent != 0, "Failed to create parent window\n");
3142 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
3143 10, 10, 100, 100, hparent, 0, 0, NULL);
3144 ok (hchild != 0, "Failed to create child window\n");
3146 ShowWindow( hparent, SW_SHOW );
3147 UpdateWindow( hparent );
3148 UpdateWindow( hchild );
3149 /* try to flush pending X expose events */
3150 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
3151 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3153 flush_sequence();
3154 log_all_parent_messages++;
3156 SetRect( &rect, 0, 0, 50, 50 );
3157 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
3158 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
3159 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
3161 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
3162 pt.x = pt.y = 0;
3163 MapWindowPoints( hchild, hparent, &pt, 1 );
3164 SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
3165 check_update_rgn( hchild, hrgn );
3166 SetRectRgn( hrgn, 0, 0, 50, 50 );
3167 check_update_rgn( hparent, hrgn );
3168 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
3169 ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
3170 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
3171 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
3173 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3174 ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
3176 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
3177 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
3178 ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
3179 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
3180 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
3182 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
3183 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
3184 ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
3186 SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
3187 flush_sequence();
3188 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
3189 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
3190 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
3192 /* flush all paint messages */
3193 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3194 flush_sequence();
3196 /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
3197 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
3198 SetRectRgn( hrgn, 0, 0, 50, 50 );
3199 check_update_rgn( hparent, hrgn );
3200 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
3201 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
3202 SetRectRgn( hrgn, 0, 0, 50, 50 );
3203 check_update_rgn( hparent, hrgn );
3205 /* flush all paint messages */
3206 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3207 SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
3208 flush_sequence();
3210 /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
3211 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
3212 SetRectRgn( hrgn, 0, 0, 50, 50 );
3213 check_update_rgn( hparent, hrgn );
3214 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
3215 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
3216 SetRectRgn( hrgn2, 10, 10, 50, 50 );
3217 CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
3218 check_update_rgn( hparent, hrgn );
3219 /* flush all paint messages */
3220 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3221 flush_sequence();
3223 /* same as above but parent gets completely validated */
3224 SetRect( &rect, 20, 20, 30, 30 );
3225 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
3226 SetRectRgn( hrgn, 20, 20, 30, 30 );
3227 check_update_rgn( hparent, hrgn );
3228 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
3229 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
3230 check_update_rgn( hparent, 0 ); /* no update region */
3231 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3232 ok_sequence( WmEmptySeq, "WmEmpty", FALSE ); /* and no paint messages */
3234 /* make sure RDW_VALIDATE on child doesn't have the same effect */
3235 flush_sequence();
3236 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
3237 SetRectRgn( hrgn, 20, 20, 30, 30 );
3238 check_update_rgn( hparent, hrgn );
3239 RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
3240 SetRectRgn( hrgn, 20, 20, 30, 30 );
3241 check_update_rgn( hparent, hrgn );
3243 /* same as above but normal WM_PAINT doesn't validate parent */
3244 flush_sequence();
3245 SetRect( &rect, 20, 20, 30, 30 );
3246 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
3247 SetRectRgn( hrgn, 20, 20, 30, 30 );
3248 check_update_rgn( hparent, hrgn );
3249 /* no WM_PAINT in child while parent still pending */
3250 while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3251 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
3252 while (PeekMessage( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3253 ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
3255 flush_sequence();
3256 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
3257 /* no WM_PAINT in child while parent still pending */
3258 while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3259 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
3260 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
3261 /* now that parent is valid child should get WM_PAINT */
3262 while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3263 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
3264 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3265 ok_sequence( WmEmptySeq, "No other message", FALSE );
3267 /* same thing with WS_CLIPCHILDREN in parent */
3268 flush_sequence();
3269 SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
3270 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
3271 /* changing style invalidates non client area, but we need to invalidate something else to see it */
3272 RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
3273 ok_sequence( WmEmptySeq, "No message", FALSE );
3274 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
3275 ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
3277 flush_sequence();
3278 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
3279 SetRectRgn( hrgn, 20, 20, 30, 30 );
3280 check_update_rgn( hparent, hrgn );
3281 /* no WM_PAINT in child while parent still pending */
3282 while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3283 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
3284 /* WM_PAINT in parent first */
3285 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3286 ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
3288 /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
3289 flush_sequence();
3290 SetRect( &rect, 0, 0, 30, 30 );
3291 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
3292 SetRectRgn( hrgn, 0, 0, 30, 30 );
3293 check_update_rgn( hparent, hrgn );
3294 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3295 ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
3297 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
3298 flush_sequence();
3299 SetRect( &rect, -10, 0, 30, 30 );
3300 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
3301 SetRect( &rect, 0, 0, 20, 20 );
3302 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
3303 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
3304 ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
3306 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
3307 flush_sequence();
3308 SetRect( &rect, -10, 0, 30, 30 );
3309 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
3310 SetRect( &rect, 0, 0, 100, 100 );
3311 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
3312 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
3313 ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
3314 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
3315 ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
3317 /* test RDW_INTERNALPAINT behavior */
3319 flush_sequence();
3320 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
3321 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3322 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
3324 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
3325 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3326 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
3328 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
3329 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3330 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
3332 SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
3333 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
3334 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
3335 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3336 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
3338 log_all_parent_messages--;
3339 DestroyWindow( hparent );
3341 DeleteObject( hrgn );
3342 DeleteObject( hrgn2 );
3345 struct wnd_event
3347 HWND hwnd;
3348 HANDLE event;
3351 static DWORD WINAPI thread_proc(void *param)
3353 MSG msg;
3354 struct wnd_event *wnd_event = (struct wnd_event *)param;
3356 wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
3357 100, 100, 200, 200, 0, 0, 0, NULL);
3358 ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
3360 SetEvent(wnd_event->event);
3362 while (GetMessage(&msg, 0, 0, 0))
3364 TranslateMessage(&msg);
3365 DispatchMessage(&msg);
3368 return 0;
3371 static void test_interthread_messages(void)
3373 HANDLE hThread;
3374 DWORD tid;
3375 WNDPROC proc;
3376 MSG msg;
3377 char buf[256];
3378 int len, expected_len;
3379 struct wnd_event wnd_event;
3380 BOOL ret;
3382 wnd_event.event = CreateEventW(NULL, 0, 0, NULL);
3383 if (!wnd_event.event)
3385 trace("skipping interthread message test under win9x\n");
3386 return;
3389 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
3390 ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError());
3392 ok(WaitForSingleObject(wnd_event.event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
3394 CloseHandle(wnd_event.event);
3396 SetLastError(0xdeadbeef);
3397 ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeded\n");
3398 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error code %ld\n", GetLastError());
3400 proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
3401 ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %ld\n", GetLastError());
3403 expected_len = lstrlenA("window caption text");
3404 memset(buf, 0, sizeof(buf));
3405 SetLastError(0xdeadbeef);
3406 len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
3407 ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %ld, len %d, expected len %d\n", GetLastError(), len, expected_len);
3408 ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
3410 msg.hwnd = wnd_event.hwnd;
3411 msg.message = WM_GETTEXT;
3412 msg.wParam = sizeof(buf);
3413 msg.lParam = (LPARAM)buf;
3414 memset(buf, 0, sizeof(buf));
3415 SetLastError(0xdeadbeef);
3416 len = DispatchMessageA(&msg);
3417 ok(!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3418 "DispatchMessageA(WM_GETTEXT) succeded on another thread window: ret %d, error %ld\n", len, GetLastError());
3420 /* the following test causes an exception in user.exe under win9x */
3421 msg.hwnd = wnd_event.hwnd;
3422 msg.message = WM_TIMER;
3423 msg.wParam = 0;
3424 msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
3425 SetLastError(0xdeadbeef);
3426 len = DispatchMessageA(&msg);
3427 ok(!len && GetLastError() == 0xdeadbeef,
3428 "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %ld\n", len, GetLastError());
3430 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
3431 ok( ret, "PostMessageA(WM_QUIT) error %ld\n", GetLastError());
3433 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
3434 CloseHandle(hThread);
3438 static const struct message WmVkN[] = {
3439 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
3440 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
3441 { WM_CHAR, wparam|lparam, 'n', 1 },
3442 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
3443 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
3444 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
3445 { 0 }
3447 static const struct message WmShiftVkN[] = {
3448 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
3449 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
3450 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
3451 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
3452 { WM_CHAR, wparam|lparam, 'N', 1 },
3453 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
3454 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
3455 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
3456 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
3457 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
3458 { 0 }
3460 static const struct message WmCtrlVkN[] = {
3461 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
3462 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
3463 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
3464 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
3465 { WM_CHAR, wparam|lparam, 0x000e, 1 },
3466 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
3467 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
3468 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
3469 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
3470 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
3471 { 0 }
3473 static const struct message WmCtrlVkN_2[] = {
3474 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
3475 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
3476 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
3477 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
3478 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
3479 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
3480 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
3481 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
3482 { 0 }
3484 static const struct message WmAltVkN[] = {
3485 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
3486 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
3487 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
3488 { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
3489 { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
3490 { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
3491 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
3492 { HCBT_SYSCOMMAND, hook },
3493 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
3494 { WM_SETCURSOR, sent|defwinproc },
3495 { WM_INITMENU, sent|defwinproc },
3496 { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
3497 { WM_CAPTURECHANGED, sent|defwinproc },
3498 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
3499 { WM_EXITMENULOOP, sent|defwinproc },
3500 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
3501 { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
3502 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
3503 { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
3504 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
3505 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
3506 { 0 }
3508 static const struct message WmAltVkN_2[] = {
3509 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
3510 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
3511 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
3512 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
3513 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
3514 { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
3515 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
3516 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
3517 { 0 }
3519 static const struct message WmCtrlAltVkN[] = {
3520 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
3521 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
3522 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
3523 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
3524 { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
3525 { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
3526 { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
3527 { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
3528 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
3529 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
3530 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
3531 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
3532 { 0 }
3535 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
3537 MSG msg;
3539 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
3541 struct message log_msg;
3543 trace("accel: %p, %04x, %08x, %08lx\n", msg.hwnd, msg.message, msg.wParam, msg.lParam);
3545 log_msg.message = msg.message;
3546 log_msg.flags = wparam|lparam;
3547 log_msg.wParam = msg.wParam;
3548 log_msg.lParam = msg.lParam;
3549 add_message(&log_msg);
3551 if (!TranslateAccelerator(hwnd, hAccel, &msg))
3553 TranslateMessage(&msg);
3554 DispatchMessage(&msg);
3559 static void test_accelerators(void)
3561 SHORT state;
3562 HACCEL hAccel;
3563 HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
3564 100, 100, 200, 200, 0, 0, 0, NULL);
3565 BOOL ret;
3567 assert(hwnd != 0);
3568 SetFocus(hwnd);
3569 ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
3571 state = GetKeyState(VK_SHIFT);
3572 ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
3573 state = GetKeyState(VK_CAPITAL);
3574 ok(state == 0, "wrong CapsLock state %04x\n", state);
3576 hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(1));
3577 assert(hAccel != 0);
3579 trace("testing VK_N press/release\n");
3580 flush_sequence();
3581 keybd_event('N', 0, 0, 0);
3582 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3583 pump_msg_loop(hwnd, hAccel);
3584 ok_sequence(WmVkN, "VK_N press/release", FALSE);
3586 trace("testing Shift+VK_N press/release\n");
3587 flush_sequence();
3588 keybd_event(VK_SHIFT, 0, 0, 0);
3589 keybd_event('N', 0, 0, 0);
3590 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3591 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
3592 pump_msg_loop(hwnd, hAccel);
3593 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
3595 trace("testing Ctrl+VK_N press/release\n");
3596 flush_sequence();
3597 keybd_event(VK_CONTROL, 0, 0, 0);
3598 keybd_event('N', 0, 0, 0);
3599 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3600 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
3601 pump_msg_loop(hwnd, hAccel);
3602 ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
3604 trace("testing Alt+VK_N press/release\n");
3605 flush_sequence();
3606 keybd_event(VK_MENU, 0, 0, 0);
3607 keybd_event('N', 0, 0, 0);
3608 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3609 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
3610 pump_msg_loop(hwnd, hAccel);
3611 ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
3613 trace("testing Ctrl+Alt+VK_N press/release\n");
3614 flush_sequence();
3615 keybd_event(VK_CONTROL, 0, 0, 0);
3616 keybd_event(VK_MENU, 0, 0, 0);
3617 keybd_event('N', 0, 0, 0);
3618 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3619 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
3620 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
3621 pump_msg_loop(hwnd, hAccel);
3622 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
3624 ret = DestroyAcceleratorTable(hAccel);
3625 ok( ret, "DestroyAcceleratorTable error %ld\n", GetLastError());
3627 hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(2));
3628 assert(hAccel != 0);
3630 trace("testing VK_N press/release\n");
3631 flush_sequence();
3632 keybd_event('N', 0, 0, 0);
3633 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3634 pump_msg_loop(hwnd, hAccel);
3635 ok_sequence(WmVkN, "VK_N press/release", FALSE);
3637 trace("testing Shift+VK_N press/release\n");
3638 flush_sequence();
3639 keybd_event(VK_SHIFT, 0, 0, 0);
3640 keybd_event('N', 0, 0, 0);
3641 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3642 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
3643 pump_msg_loop(hwnd, hAccel);
3644 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
3646 trace("testing Ctrl+VK_N press/release 2\n");
3647 flush_sequence();
3648 keybd_event(VK_CONTROL, 0, 0, 0);
3649 keybd_event('N', 0, 0, 0);
3650 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3651 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
3652 pump_msg_loop(hwnd, hAccel);
3653 ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
3655 trace("testing Alt+VK_N press/release 2\n");
3656 flush_sequence();
3657 keybd_event(VK_MENU, 0, 0, 0);
3658 keybd_event('N', 0, 0, 0);
3659 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3660 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
3661 pump_msg_loop(hwnd, hAccel);
3662 ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
3664 trace("testing Ctrl+Alt+VK_N press/release\n");
3665 flush_sequence();
3666 keybd_event(VK_CONTROL, 0, 0, 0);
3667 keybd_event(VK_MENU, 0, 0, 0);
3668 keybd_event('N', 0, 0, 0);
3669 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3670 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
3671 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
3672 pump_msg_loop(hwnd, hAccel);
3673 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
3675 ret = DestroyAcceleratorTable(hAccel);
3676 ok( ret, "DestroyAcceleratorTable error %ld\n", GetLastError());
3678 DestroyWindow(hwnd);
3681 /************* window procedures ********************/
3683 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3685 static long defwndproc_counter = 0;
3686 static long beginpaint_counter = 0;
3687 LRESULT ret;
3688 struct message msg;
3690 trace("%p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
3692 switch (message)
3694 case WM_WINDOWPOSCHANGING:
3695 case WM_WINDOWPOSCHANGED:
3697 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
3699 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
3700 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
3701 winpos->hwnd, winpos->hwndInsertAfter,
3702 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
3704 /* Log only documented flags, win2k uses 0x1000 and 0x2000
3705 * in the high word for internal purposes
3707 wParam = winpos->flags & 0xffff;
3708 break;
3712 msg.message = message;
3713 msg.flags = sent|wparam|lparam;
3714 if (defwndproc_counter) msg.flags |= defwinproc;
3715 if (beginpaint_counter) msg.flags |= beginpaint;
3716 msg.wParam = wParam;
3717 msg.lParam = lParam;
3718 add_message(&msg);
3720 if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
3722 HWND parent = GetParent(hwnd);
3723 RECT rc;
3724 MINMAXINFO *minmax = (MINMAXINFO *)lParam;
3726 GetClientRect(parent, &rc);
3727 trace("parent %p client size = (%ld x %ld)\n", parent, rc.right, rc.bottom);
3729 trace("ptReserved = (%ld,%ld)\n"
3730 "ptMaxSize = (%ld,%ld)\n"
3731 "ptMaxPosition = (%ld,%ld)\n"
3732 "ptMinTrackSize = (%ld,%ld)\n"
3733 "ptMaxTrackSize = (%ld,%ld)\n",
3734 minmax->ptReserved.x, minmax->ptReserved.y,
3735 minmax->ptMaxSize.x, minmax->ptMaxSize.y,
3736 minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
3737 minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
3738 minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
3740 ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %ld != %ld\n",
3741 minmax->ptMaxSize.x, rc.right);
3742 ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %ld != %ld\n",
3743 minmax->ptMaxSize.y, rc.bottom);
3746 if (message == WM_PAINT)
3748 PAINTSTRUCT ps;
3749 beginpaint_counter++;
3750 BeginPaint( hwnd, &ps );
3751 beginpaint_counter--;
3752 EndPaint( hwnd, &ps );
3753 return 0;
3756 defwndproc_counter++;
3757 ret = DefWindowProcA(hwnd, message, wParam, lParam);
3758 defwndproc_counter--;
3760 return ret;
3763 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3765 static long defwndproc_counter = 0;
3766 LRESULT ret;
3767 struct message msg;
3769 trace("popup: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
3771 msg.message = message;
3772 msg.flags = sent|wparam|lparam;
3773 if (defwndproc_counter) msg.flags |= defwinproc;
3774 msg.wParam = wParam;
3775 msg.lParam = lParam;
3776 add_message(&msg);
3778 if (message == WM_CREATE)
3780 DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
3781 SetWindowLongA(hwnd, GWL_STYLE, style);
3784 defwndproc_counter++;
3785 ret = DefWindowProcA(hwnd, message, wParam, lParam);
3786 defwndproc_counter--;
3788 return ret;
3791 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3793 static long defwndproc_counter = 0;
3794 static long beginpaint_counter = 0;
3795 LRESULT ret;
3796 struct message msg;
3798 trace("parent: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
3800 if (log_all_parent_messages ||
3801 message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
3802 message == WM_SETFOCUS || message == WM_KILLFOCUS ||
3803 message == WM_ENABLE || message == WM_ENTERIDLE ||
3804 message == WM_IME_SETCONTEXT)
3806 msg.message = message;
3807 msg.flags = sent|parent|wparam|lparam;
3808 if (defwndproc_counter) msg.flags |= defwinproc;
3809 if (beginpaint_counter) msg.flags |= beginpaint;
3810 msg.wParam = wParam;
3811 msg.lParam = lParam;
3812 add_message(&msg);
3815 if (message == WM_PAINT)
3817 PAINTSTRUCT ps;
3818 beginpaint_counter++;
3819 BeginPaint( hwnd, &ps );
3820 beginpaint_counter--;
3821 EndPaint( hwnd, &ps );
3822 return 0;
3825 defwndproc_counter++;
3826 ret = DefWindowProcA(hwnd, message, wParam, lParam);
3827 defwndproc_counter--;
3829 return ret;
3832 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3834 static long defwndproc_counter = 0;
3835 LRESULT ret;
3836 struct message msg;
3838 trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
3840 DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
3841 ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
3842 if (after_end_dialog)
3843 ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
3844 else
3845 ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
3847 msg.message = message;
3848 msg.flags = sent|wparam|lparam;
3849 if (defwndproc_counter) msg.flags |= defwinproc;
3850 msg.wParam = wParam;
3851 msg.lParam = lParam;
3852 add_message(&msg);
3854 defwndproc_counter++;
3855 ret = DefDlgProcA(hwnd, message, wParam, lParam);
3856 defwndproc_counter--;
3858 return ret;
3861 static BOOL RegisterWindowClasses(void)
3863 WNDCLASSA cls;
3865 cls.style = 0;
3866 cls.lpfnWndProc = MsgCheckProcA;
3867 cls.cbClsExtra = 0;
3868 cls.cbWndExtra = 0;
3869 cls.hInstance = GetModuleHandleA(0);
3870 cls.hIcon = 0;
3871 cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
3872 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
3873 cls.lpszMenuName = NULL;
3874 cls.lpszClassName = "TestWindowClass";
3875 if(!RegisterClassA(&cls)) return FALSE;
3877 cls.lpfnWndProc = PopupMsgCheckProcA;
3878 cls.lpszClassName = "TestPopupClass";
3879 if(!RegisterClassA(&cls)) return FALSE;
3881 cls.lpfnWndProc = ParentMsgCheckProcA;
3882 cls.lpszClassName = "TestParentClass";
3883 if(!RegisterClassA(&cls)) return FALSE;
3885 cls.lpfnWndProc = DefWindowProcA;
3886 cls.lpszClassName = "SimpleWindowClass";
3887 if(!RegisterClassA(&cls)) return FALSE;
3889 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
3890 cls.lpfnWndProc = TestDlgProcA;
3891 cls.lpszClassName = "TestDialogClass";
3892 if(!RegisterClassA(&cls)) return FALSE;
3894 return TRUE;
3897 static HHOOK hCBT_hook;
3899 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
3901 char buf[256];
3903 trace("CBT: %d, %08x, %08lx\n", nCode, wParam, lParam);
3905 if (nCode == HCBT_SYSCOMMAND)
3907 struct message msg;
3909 msg.message = nCode;
3910 msg.flags = hook;
3911 msg.wParam = wParam;
3912 msg.lParam = lParam;
3913 add_message(&msg);
3915 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
3918 /* Log also SetFocus(0) calls */
3919 if (!wParam) wParam = lParam;
3921 if (GetClassNameA((HWND)wParam, buf, sizeof(buf)))
3923 if (!strcmp(buf, "TestWindowClass") ||
3924 !strcmp(buf, "TestParentClass") ||
3925 !strcmp(buf, "TestPopupClass") ||
3926 !strcmp(buf, "SimpleWindowClass") ||
3927 !strcmp(buf, "TestDialogClass") ||
3928 !strcmp(buf, "MDI_frame_class") ||
3929 !strcmp(buf, "MDI_client_class") ||
3930 !strcmp(buf, "MDI_child_class") ||
3931 !strcmp(buf, "my_button_class") ||
3932 !strcmp(buf, "#32770"))
3934 struct message msg;
3936 msg.message = nCode;
3937 msg.flags = hook;
3938 msg.wParam = wParam;
3939 msg.lParam = lParam;
3940 add_message(&msg);
3943 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
3946 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
3947 static const WCHAR wszAnsi[] = {'U',0};
3949 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
3951 switch (uMsg)
3953 case CB_FINDSTRINGEXACT:
3954 trace("String: %p\n", (LPCWSTR)lParam);
3955 if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
3956 return 1;
3957 if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
3958 return 0;
3959 return -1;
3961 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
3964 static void test_message_conversion(void)
3966 static const WCHAR wszMsgConversionClass[] =
3967 {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
3968 WNDCLASSW cls;
3969 LRESULT lRes;
3970 HWND hwnd;
3971 WNDPROC wndproc;
3973 cls.style = 0;
3974 cls.lpfnWndProc = MsgConversionProcW;
3975 cls.cbClsExtra = 0;
3976 cls.cbWndExtra = 0;
3977 cls.hInstance = GetModuleHandleW(NULL);
3978 cls.hIcon = NULL;
3979 cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
3980 cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
3981 cls.lpszMenuName = NULL;
3982 cls.lpszClassName = wszMsgConversionClass;
3983 /* this call will fail on Win9x, but that doesn't matter as this test is
3984 * meaningless on those platforms */
3985 if(!RegisterClassW(&cls)) return;
3987 hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
3988 100, 100, 200, 200, 0, 0, 0, NULL);
3989 ok(hwnd != NULL, "Window creation failed\n");
3991 /* {W, A} -> A */
3993 wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
3994 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3995 ok(lRes == 0, "String should have been converted\n");
3996 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3997 ok(lRes == 1, "String shouldn't have been converted\n");
3999 /* {W, A} -> W */
4001 wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
4002 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4003 ok(lRes == 1, "String shouldn't have been converted\n");
4004 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4005 ok(lRes == 1, "String shouldn't have been converted\n");
4007 /* Synchronous messages */
4009 lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4010 ok(lRes == 0, "String should have been converted\n");
4011 lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4012 ok(lRes == 1, "String shouldn't have been converted\n");
4014 /* Asynchronous messages */
4016 SetLastError(0);
4017 lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4018 ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4019 "PostMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4020 SetLastError(0);
4021 lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4022 ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4023 "PostMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4024 SetLastError(0);
4025 lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4026 ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4027 "PosThreadtMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4028 SetLastError(0);
4029 lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4030 ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4031 "PosThreadtMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4032 SetLastError(0);
4033 lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4034 ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4035 "SendNotifyMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4036 SetLastError(0);
4037 lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4038 ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4039 "SendNotifyMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4040 SetLastError(0);
4041 lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
4042 ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4043 "SendMessageCallback on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4044 SetLastError(0);
4045 lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
4046 ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4047 "SendMessageCallback on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4050 typedef struct _thread_info
4052 HWND hWnd;
4053 HANDLE handles[2];
4054 DWORD id;
4055 } thread_info;
4057 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT id, DWORD dwTime)
4061 #define TIMER_ID 0x19
4063 static DWORD WINAPI timer_thread_proc(LPVOID x)
4065 thread_info *info = x;
4066 DWORD r;
4068 r = KillTimer(info->hWnd, 0x19);
4069 ok(r,"KillTimer failed in thread\n");
4070 r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
4071 ok(r,"SetTimer failed in thread\n");
4072 ok(r==TIMER_ID,"SetTimer id different\n");
4073 r = SetEvent(info->handles[0]);
4074 ok(r,"SetEvent failed in thread\n");
4075 return 0;
4078 static void test_timers(void)
4080 thread_info info;
4081 DWORD id;
4083 info.hWnd = CreateWindow ("TestWindowClass", NULL,
4084 WS_OVERLAPPEDWINDOW ,
4085 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4086 NULL, NULL, 0);
4088 info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
4089 ok(info.id, "SetTimer failed\n");
4090 ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
4091 info.handles[0] = CreateEvent(NULL,0,0,NULL);
4092 info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
4094 WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
4096 WaitForSingleObject(info.handles[1], INFINITE);
4098 ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
4100 ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
4103 START_TEST(msg)
4105 if (!RegisterWindowClasses()) assert(0);
4107 hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
4108 assert(hCBT_hook);
4110 test_messages();
4111 test_mdi_messages();
4112 test_button_messages();
4113 test_paint_messages();
4114 test_interthread_messages();
4115 test_message_conversion();
4116 test_accelerators();
4117 test_timers();
4119 UnhookWindowsHookEx(hCBT_hook);