- WM_MDISETMENU handler should update new frame menu only if an active
[wine/multimedia.git] / dlls / user / tests / msg.c
blobf8972f8617419551a6b5bff31c488d4b65bccd51
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;
773 static void add_message(const struct message *msg)
775 if (!sequence)
777 sequence_size = 10;
778 sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof (struct message) );
780 if (sequence_cnt == sequence_size)
782 sequence_size *= 2;
783 sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof (struct message) );
785 assert(sequence);
787 sequence[sequence_cnt].message = msg->message;
788 sequence[sequence_cnt].flags = msg->flags;
789 sequence[sequence_cnt].wParam = msg->wParam;
790 sequence[sequence_cnt].lParam = msg->lParam;
792 sequence_cnt++;
795 static void flush_sequence()
797 HeapFree(GetProcessHeap(), 0, sequence);
798 sequence = 0;
799 sequence_cnt = sequence_size = 0;
802 static void ok_sequence(const struct message *expected, const char *context, int todo)
804 static const struct message end_of_sequence = { 0, 0, 0, 0 };
805 const struct message *actual;
807 add_message(&end_of_sequence);
809 actual = sequence;
811 while (expected->message && actual->message)
813 trace("expected %04x - actual %04x\n", expected->message, actual->message);
815 if (expected->message == actual->message)
817 if (expected->flags & wparam)
819 if (expected->wParam != actual->wParam && todo)
821 todo_wine {
822 ok (FALSE,
823 "%s: in msg 0x%04x expecting wParam 0x%x got 0x%x\n",
824 context, expected->message, expected->wParam, actual->wParam);
827 else
828 ok (expected->wParam == actual->wParam,
829 "%s: in msg 0x%04x expecting wParam 0x%x got 0x%x\n",
830 context, expected->message, expected->wParam, actual->wParam);
832 if (expected->flags & lparam)
833 ok (expected->lParam == actual->lParam,
834 "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
835 context, expected->message, expected->lParam, actual->lParam);
836 ok ((expected->flags & defwinproc) == (actual->flags & defwinproc),
837 "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
838 context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
839 ok ((expected->flags & beginpaint) == (actual->flags & beginpaint),
840 "%s: the msg 0x%04x should %shave been sent by BeginPaint\n",
841 context, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
842 ok ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
843 "%s: the msg 0x%04x should have been %s\n",
844 context, expected->message, (expected->flags & posted) ? "posted" : "sent");
845 ok ((expected->flags & parent) == (actual->flags & parent),
846 "%s: the msg 0x%04x was expected in %s\n",
847 context, expected->message, (expected->flags & parent) ? "parent" : "child");
848 ok ((expected->flags & hook) == (actual->flags & hook),
849 "%s: the msg 0x%04x should have been sent by a hook\n",
850 context, expected->message);
851 expected++;
852 actual++;
854 else if (expected->flags & optional)
855 expected++;
856 else if (todo)
858 todo_wine {
859 ok (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
860 context, expected->message, actual->message);
862 flush_sequence();
863 return;
865 else
867 ok (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
868 context, expected->message, actual->message);
869 expected++;
870 actual++;
874 /* skip all optional trailing messages */
875 while (expected->message && (expected->flags & optional))
876 expected++;
878 if (todo)
880 todo_wine {
881 if (expected->message || actual->message)
882 ok (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
883 context, expected->message, actual->message);
886 else
888 if (expected->message || actual->message)
889 ok (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
890 context, expected->message, actual->message);
893 flush_sequence();
896 /******************************** MDI test **********************************/
898 /* CreateWindow for MDI frame window, initially visible */
899 static const struct message WmCreateMDIframeSeq[] = {
900 { HCBT_CREATEWND, hook },
901 { WM_GETMINMAXINFO, sent },
902 { WM_NCCREATE, sent },
903 { WM_NCCALCSIZE, sent|wparam, 0 },
904 { WM_CREATE, sent },
905 { WM_SHOWWINDOW, sent|wparam, 1 },
906 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
907 { HCBT_ACTIVATE, hook },
908 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
909 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
910 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* Win9x */
911 { WM_ACTIVATEAPP, sent|wparam, 1 },
912 { WM_NCACTIVATE, sent|wparam, 1 },
913 { WM_ACTIVATE, sent|wparam, 1 },
914 { HCBT_SETFOCUS, hook },
915 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
916 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
917 /* Win9x adds SWP_NOZORDER below */
918 { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
919 { WM_SIZE, sent },
920 { WM_MOVE, sent },
921 { 0 }
923 /* DestroyWindow for MDI frame window, initially visible */
924 static const struct message WmDestroyMDIframeSeq[] = {
925 { HCBT_DESTROYWND, hook },
926 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
927 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
928 { WM_NCACTIVATE, sent|wparam, 0 },
929 { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
930 { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
931 { WM_DESTROY, sent },
932 { WM_NCDESTROY, sent },
933 { 0 }
935 /* CreateWindow for MDI client window, initially visible */
936 static const struct message WmCreateMDIclientSeq[] = {
937 { HCBT_CREATEWND, hook },
938 { WM_NCCREATE, sent },
939 { WM_NCCALCSIZE, sent|wparam, 0 },
940 { WM_CREATE, sent },
941 { WM_SIZE, sent },
942 { WM_MOVE, sent },
943 { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
944 { WM_SHOWWINDOW, sent|wparam, 1 },
945 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE|SWP_NOMOVE },
946 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
947 { 0 }
949 /* DestroyWindow for MDI client window, initially visible */
950 static const struct message WmDestroyMDIclientSeq[] = {
951 { HCBT_DESTROYWND, hook },
952 { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
953 { WM_SHOWWINDOW, sent|wparam, 0 },
954 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
955 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
956 { WM_DESTROY, sent },
957 { WM_NCDESTROY, sent },
958 { 0 }
960 /* CreateWindow for MDI child window, initially visible */
961 static const struct message WmCreateMDIchildVisibleSeq[] = {
962 { HCBT_CREATEWND, hook },
963 { WM_NCCREATE, sent },
964 { WM_NCCALCSIZE, sent|wparam, 0 },
965 { WM_CREATE, sent },
966 { WM_SIZE, sent },
967 { WM_MOVE, sent },
968 /* Win2k sends wparam set to
969 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
970 * while Win9x doesn't bother to set child window id according to
971 * CLIENTCREATESTRUCT.idFirstChild
973 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
974 { WM_SHOWWINDOW, sent|wparam, 1 },
975 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
976 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
977 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
978 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
979 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
980 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
982 /* Win9x: message sequence terminates here. */
984 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
985 { HCBT_SETFOCUS, hook }, /* in MDI client */
986 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
987 { WM_SETFOCUS, sent }, /* in MDI client */
988 { HCBT_SETFOCUS, hook },
989 { WM_KILLFOCUS, sent }, /* in MDI client */
990 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
991 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
992 { WM_SETFOCUS, sent|defwinproc },
993 { WM_MDIACTIVATE, sent|defwinproc },
994 { 0 }
996 /* DestroyWindow for MDI child window, initially visible */
997 static const struct message WmDestroyMDIchildVisibleSeq[] = {
998 { HCBT_DESTROYWND, hook },
999 /* Win2k sends wparam set to
1000 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1001 * while Win9x doesn't bother to set child window id according to
1002 * CLIENTCREATESTRUCT.idFirstChild
1004 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1005 { WM_SHOWWINDOW, sent|wparam, 0 },
1006 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1007 { WM_ERASEBKGND, sent|parent|optional },
1008 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1010 /* { WM_DESTROY, sent }
1011 * Win9x: message sequence terminates here.
1014 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1015 { WM_KILLFOCUS, sent },
1016 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1017 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1018 { WM_SETFOCUS, sent }, /* in MDI client */
1020 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1021 { WM_KILLFOCUS, sent }, /* in MDI client */
1022 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1023 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1024 { WM_SETFOCUS, sent }, /* in MDI client */
1026 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1027 { WM_KILLFOCUS, sent },
1028 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1029 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1030 { WM_SETFOCUS, sent }, /* in MDI client */
1032 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1033 { WM_KILLFOCUS, sent }, /* in MDI client */
1034 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1035 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1036 { WM_SETFOCUS, sent }, /* in MDI client */
1038 { WM_DESTROY, sent },
1040 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1041 { WM_KILLFOCUS, sent },
1042 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1043 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1044 { WM_SETFOCUS, sent }, /* in MDI client */
1046 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1047 { WM_KILLFOCUS, sent }, /* in MDI client */
1048 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1049 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1050 { WM_SETFOCUS, sent }, /* in MDI client */
1052 { WM_NCDESTROY, sent },
1053 { 0 }
1055 /* CreateWindow for MDI child window, initially invisible */
1056 static const struct message WmCreateMDIchildInvisibleSeq[] = {
1057 { HCBT_CREATEWND, hook },
1058 { WM_NCCREATE, sent },
1059 { WM_NCCALCSIZE, sent|wparam, 0 },
1060 { WM_CREATE, sent },
1061 { WM_SIZE, sent },
1062 { WM_MOVE, sent },
1063 /* Win2k sends wparam set to
1064 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1065 * while Win9x doesn't bother to set child window id according to
1066 * CLIENTCREATESTRUCT.idFirstChild
1068 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1069 { 0 }
1071 /* DestroyWindow for MDI child window, initially invisible */
1072 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
1073 { HCBT_DESTROYWND, hook },
1074 /* Win2k sends wparam set to
1075 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1076 * while Win9x doesn't bother to set child window id according to
1077 * CLIENTCREATESTRUCT.idFirstChild
1079 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1080 { WM_DESTROY, sent },
1081 { WM_NCDESTROY, sent },
1082 { 0 }
1084 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
1085 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
1086 { HCBT_CREATEWND, hook },
1087 { WM_NCCREATE, sent },
1088 { WM_NCCALCSIZE, sent|wparam, 0 },
1089 { WM_CREATE, sent },
1090 { WM_SIZE, sent },
1091 { WM_MOVE, sent },
1092 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1093 { WM_GETMINMAXINFO, sent },
1094 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
1095 { WM_NCCALCSIZE, sent|wparam, 1 },
1096 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1097 { WM_SIZE, sent|defwinproc },
1098 /* in MDI frame */
1099 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1100 { WM_NCCALCSIZE, sent|wparam, 1 },
1101 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1102 /* Win2k sends wparam set to
1103 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1104 * while Win9x doesn't bother to set child window id according to
1105 * CLIENTCREATESTRUCT.idFirstChild
1107 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1108 { WM_SHOWWINDOW, sent|wparam, 1 },
1109 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1110 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1111 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1112 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1113 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1114 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1116 /* Win9x: message sequence terminates here. */
1118 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1119 { HCBT_SETFOCUS, hook }, /* in MDI client */
1120 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1121 { WM_SETFOCUS, sent }, /* in MDI client */
1122 { HCBT_SETFOCUS, hook },
1123 { WM_KILLFOCUS, sent }, /* in MDI client */
1124 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1125 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1126 { WM_SETFOCUS, sent|defwinproc },
1127 { WM_MDIACTIVATE, sent|defwinproc },
1128 /* in MDI frame */
1129 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1130 { WM_NCCALCSIZE, sent|wparam, 1 },
1131 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1132 { 0 }
1134 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
1135 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
1136 /* restore the 1st MDI child */
1137 { WM_SETREDRAW, sent|wparam, 0 },
1138 { HCBT_MINMAX, hook },
1139 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
1140 { WM_NCCALCSIZE, sent|wparam, 1 },
1141 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1142 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1143 { WM_SIZE, sent|defwinproc },
1144 /* in MDI frame */
1145 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1146 { WM_NCCALCSIZE, sent|wparam, 1 },
1147 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1148 { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
1149 /* create the 2nd MDI child */
1150 { HCBT_CREATEWND, hook },
1151 { WM_NCCREATE, sent },
1152 { WM_NCCALCSIZE, sent|wparam, 0 },
1153 { WM_CREATE, sent },
1154 { WM_SIZE, sent },
1155 { WM_MOVE, sent },
1156 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1157 { WM_GETMINMAXINFO, sent },
1158 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
1159 { WM_NCCALCSIZE, sent|wparam, 1 },
1160 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1161 { WM_SIZE, sent|defwinproc },
1162 /* in MDI frame */
1163 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1164 { WM_NCCALCSIZE, sent|wparam, 1 },
1165 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1166 /* Win2k sends wparam set to
1167 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1168 * while Win9x doesn't bother to set child window id according to
1169 * CLIENTCREATESTRUCT.idFirstChild
1171 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1172 { WM_SHOWWINDOW, sent|wparam, 1 },
1173 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1174 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1175 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1176 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1177 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1179 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
1180 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
1182 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1184 /* Win9x: message sequence terminates here. */
1186 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1187 { HCBT_SETFOCUS, hook },
1188 { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
1189 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
1190 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1191 { WM_SETFOCUS, sent }, /* in MDI client */
1192 { HCBT_SETFOCUS, hook },
1193 { WM_KILLFOCUS, sent }, /* in MDI client */
1194 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1195 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1196 { WM_SETFOCUS, sent|defwinproc },
1198 { WM_MDIACTIVATE, sent|defwinproc },
1199 /* in MDI frame */
1200 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1201 { WM_NCCALCSIZE, sent|wparam, 1 },
1202 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1203 { 0 }
1205 /* WM_MDICREATE MDI child window, initially visible and maximized */
1206 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
1207 { WM_MDICREATE, sent },
1208 { HCBT_CREATEWND, hook },
1209 { WM_NCCREATE, sent },
1210 { WM_NCCALCSIZE, sent|wparam, 0 },
1211 { WM_CREATE, sent },
1212 { WM_SIZE, sent },
1213 { WM_MOVE, sent },
1214 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1215 { WM_GETMINMAXINFO, sent },
1216 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
1217 { WM_NCCALCSIZE, sent|wparam, 1 },
1218 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1219 { WM_SIZE, sent|defwinproc },
1220 /* in MDI frame */
1221 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1222 { WM_NCCALCSIZE, sent|wparam, 1 },
1223 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1224 /* Win2k sends wparam set to
1225 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1226 * while Win9x doesn't bother to set child window id according to
1227 * CLIENTCREATESTRUCT.idFirstChild
1229 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1230 { WM_SHOWWINDOW, sent|wparam, 1 },
1231 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1232 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1233 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1234 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1235 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1236 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1238 /* Win9x: message sequence terminates here. */
1240 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1241 { HCBT_SETFOCUS, hook }, /* in MDI client */
1242 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1243 { WM_SETFOCUS, sent }, /* in MDI client */
1244 { HCBT_SETFOCUS, hook },
1245 { WM_KILLFOCUS, sent }, /* in MDI client */
1246 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1247 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1248 { WM_SETFOCUS, sent|defwinproc },
1250 { WM_MDIACTIVATE, sent|defwinproc },
1252 /* in MDI child */
1253 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1254 { WM_NCCALCSIZE, sent|wparam, 1 },
1255 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1257 /* in MDI frame */
1258 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1259 { WM_NCCALCSIZE, sent|wparam, 1 },
1260 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1261 { WM_MOVE, sent|defwinproc },
1262 { WM_SIZE, sent|defwinproc },
1264 /* in MDI client */
1265 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
1266 { WM_NCCALCSIZE, sent|wparam, 1 },
1267 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
1268 { WM_SIZE, sent },
1270 /* in MDI child */
1271 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
1272 { WM_NCCALCSIZE, sent|wparam, 1 },
1273 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
1274 { WM_SIZE, sent|defwinproc },
1276 { 0 }
1278 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
1279 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
1280 { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
1281 { HCBT_SYSCOMMAND, hook },
1282 { WM_CLOSE, sent|defwinproc },
1283 { WM_MDIDESTROY, sent }, /* in MDI client */
1285 /* bring the 1st MDI child to top */
1286 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
1287 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
1288 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
1289 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
1290 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
1292 /* maximize the 1st MDI child */
1293 { HCBT_MINMAX, hook },
1294 { WM_GETMINMAXINFO, sent|defwinproc },
1295 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|0x8000 },
1296 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
1297 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
1298 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1299 { WM_SIZE, sent|defwinproc },
1301 /* restore the 2nd MDI child */
1302 { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
1303 { HCBT_MINMAX, hook },
1304 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOZORDER|0x8000 },
1305 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
1306 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1307 { WM_SIZE, sent|defwinproc },
1308 { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
1309 /* in MDI frame */
1310 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1311 { WM_NCCALCSIZE, sent|wparam, 1 },
1312 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1314 /* bring the 1st MDI child to top */
1315 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1316 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1317 { HCBT_SETFOCUS, hook },
1318 { WM_KILLFOCUS, sent|defwinproc },
1319 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
1320 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1321 { WM_SETFOCUS, sent }, /* in MDI client */
1322 { HCBT_SETFOCUS, hook },
1323 { WM_KILLFOCUS, sent }, /* in MDI client */
1324 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1325 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1326 { WM_SETFOCUS, sent|defwinproc },
1327 { WM_MDIACTIVATE, sent|defwinproc },
1328 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1330 /* apparently ShowWindow(SW_SHOW) on an MDI client */
1331 { WM_SHOWWINDOW, sent|wparam, 1 },
1332 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1333 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1334 { WM_MDIREFRESHMENU, sent },
1336 { HCBT_DESTROYWND, hook },
1337 /* Win2k sends wparam set to
1338 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1339 * while Win9x doesn't bother to set child window id according to
1340 * CLIENTCREATESTRUCT.idFirstChild
1342 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1343 { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
1344 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1345 { WM_ERASEBKGND, sent|parent|optional },
1346 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1348 { WM_DESTROY, sent|defwinproc },
1349 { WM_NCDESTROY, sent|defwinproc },
1350 { 0 }
1352 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
1353 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
1354 { WM_MDIDESTROY, sent }, /* in MDI client */
1355 { WM_SHOWWINDOW, sent|wparam, 0 },
1356 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1357 { WM_ERASEBKGND, sent|parent|optional },
1358 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1360 { HCBT_SETFOCUS, hook },
1361 { WM_KILLFOCUS, sent },
1362 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1363 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1364 { WM_SETFOCUS, sent }, /* in MDI client */
1365 { HCBT_SETFOCUS, hook },
1366 { WM_KILLFOCUS, sent }, /* in MDI client */
1367 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1368 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1369 { WM_SETFOCUS, sent },
1371 /* in MDI child */
1372 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1373 { WM_NCCALCSIZE, sent|wparam, 1 },
1374 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1376 /* in MDI frame */
1377 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1378 { WM_NCCALCSIZE, sent|wparam, 1 },
1379 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1380 { WM_MOVE, sent|defwinproc },
1381 { WM_SIZE, sent|defwinproc },
1383 /* in MDI client */
1384 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
1385 { WM_NCCALCSIZE, sent|wparam, 1 },
1386 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
1387 { WM_SIZE, sent },
1389 /* in MDI child */
1390 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
1391 { WM_NCCALCSIZE, sent|wparam, 1 },
1392 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
1393 { WM_SIZE, sent|defwinproc },
1395 /* in MDI child */
1396 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1397 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
1398 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1400 /* in MDI frame */
1401 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1402 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
1403 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1404 { WM_MOVE, sent|defwinproc },
1405 { WM_SIZE, sent|defwinproc },
1407 /* in MDI client */
1408 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
1409 { WM_NCCALCSIZE, sent|wparam, 1 },
1410 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
1411 { WM_SIZE, sent },
1413 /* in MDI child */
1414 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOZORDER },
1415 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
1416 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
1417 { WM_SIZE, sent|defwinproc },
1419 /* in MDI frame */
1420 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1421 { WM_NCCALCSIZE, sent|wparam, 1 },
1422 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1424 { WM_NCACTIVATE, sent|wparam, 0 },
1425 { WM_MDIACTIVATE, sent },
1427 { HCBT_MINMAX, hook },
1428 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|0x8000 },
1429 { WM_NCCALCSIZE, sent|wparam, 1 },
1430 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1431 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE|0x8000 },
1432 { WM_SIZE, sent|defwinproc },
1434 /* in MDI child */
1435 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1436 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
1437 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1439 /* in MDI frame */
1440 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1441 { WM_NCCALCSIZE, sent|wparam, 1 },
1442 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1443 { WM_MOVE, sent|defwinproc },
1444 { WM_SIZE, sent|defwinproc },
1446 /* in MDI client */
1447 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
1448 { WM_NCCALCSIZE, sent|wparam, 1 },
1449 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
1450 { WM_SIZE, sent },
1452 { HCBT_SETFOCUS, hook },
1453 { WM_KILLFOCUS, sent },
1454 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1455 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1456 { WM_SETFOCUS, sent }, /* in MDI client */
1458 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
1460 { HCBT_DESTROYWND, hook },
1461 /* Win2k sends wparam set to
1462 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1463 * while Win9x doesn't bother to set child window id according to
1464 * CLIENTCREATESTRUCT.idFirstChild
1466 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1468 { WM_SHOWWINDOW, sent|wparam, 0 },
1469 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1470 { WM_ERASEBKGND, sent|parent|optional },
1471 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1473 { WM_DESTROY, sent },
1474 { WM_NCDESTROY, sent },
1475 { 0 }
1477 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
1478 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
1479 { HCBT_MINMAX, hook },
1480 { WM_GETMINMAXINFO, sent },
1481 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
1482 { WM_NCCALCSIZE, sent|wparam, 1 },
1483 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1485 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1486 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1487 { HCBT_SETFOCUS, hook },
1488 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1489 { WM_SETFOCUS, sent }, /* in MDI client */
1490 { HCBT_SETFOCUS, hook },
1491 { WM_KILLFOCUS, sent }, /* in MDI client */
1492 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1493 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1494 { WM_SETFOCUS, sent|defwinproc },
1495 { WM_MDIACTIVATE, sent|defwinproc },
1496 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1497 { WM_SIZE, sent|defwinproc },
1498 /* in MDI frame */
1499 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1500 { WM_NCCALCSIZE, sent|wparam, 1 },
1501 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1502 { 0 }
1504 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
1505 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
1506 { HCBT_MINMAX, hook },
1507 { WM_GETMINMAXINFO, sent },
1508 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
1509 { WM_NCCALCSIZE, sent|wparam, 1 },
1510 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1511 { WM_WINDOWPOSCHANGED, sent|wparam, 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_RESTORE) for a visible MDI child window */
1520 static const struct message WmRestoreMDIchildVisibleSeq[] = {
1521 { HCBT_MINMAX, hook },
1522 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
1523 { WM_NCCALCSIZE, sent|wparam, 1 },
1524 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1525 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1526 { WM_SIZE, sent|defwinproc },
1527 /* in MDI frame */
1528 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1529 { WM_NCCALCSIZE, sent|wparam, 1 },
1530 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1531 { 0 }
1533 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
1534 static const struct message WmRestoreMDIchildInisibleSeq[] = {
1535 { HCBT_MINMAX, hook },
1536 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
1537 { WM_NCCALCSIZE, sent|wparam, 1 },
1538 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1539 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1540 { WM_SIZE, sent|defwinproc },
1541 /* in MDI frame */
1542 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1543 { WM_NCCALCSIZE, sent|wparam, 1 },
1544 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1545 { 0 }
1548 static HWND mdi_client;
1549 static WNDPROC old_mdi_client_proc;
1551 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1553 struct message msg;
1555 /* do not log painting messages */
1556 if (message != WM_PAINT &&
1557 message != WM_ERASEBKGND &&
1558 message != WM_NCPAINT &&
1559 message != WM_GETTEXT &&
1560 message != WM_MDIGETACTIVE)
1562 trace("mdi client: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1564 switch (message)
1566 case WM_WINDOWPOSCHANGING:
1567 case WM_WINDOWPOSCHANGED:
1569 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
1571 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
1572 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
1573 winpos->hwnd, winpos->hwndInsertAfter,
1574 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
1576 /* Log only documented flags, win2k uses 0x1000 and 0x2000
1577 * in the high word for internal purposes
1579 wParam = winpos->flags & 0xffff;
1580 break;
1584 msg.message = message;
1585 msg.flags = sent|wparam|lparam;
1586 msg.wParam = wParam;
1587 msg.lParam = lParam;
1588 add_message(&msg);
1591 return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
1594 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1596 static long defwndproc_counter = 0;
1597 LRESULT ret;
1598 struct message msg;
1600 /* do not log painting messages */
1601 if (message != WM_PAINT &&
1602 message != WM_ERASEBKGND &&
1603 message != WM_NCPAINT &&
1604 message != WM_GETTEXT)
1606 trace("mdi child: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1608 switch (message)
1610 case WM_WINDOWPOSCHANGING:
1611 case WM_WINDOWPOSCHANGED:
1613 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
1615 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
1616 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
1617 winpos->hwnd, winpos->hwndInsertAfter,
1618 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
1620 /* Log only documented flags, win2k uses 0x1000 and 0x2000
1621 * in the high word for internal purposes
1623 wParam = winpos->flags & 0xffff;
1624 break;
1627 case WM_MDIACTIVATE:
1629 HWND active, client = GetParent(hwnd);
1631 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
1633 if (hwnd == (HWND)lParam) /* if we are being activated */
1634 ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
1635 else
1636 ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
1637 break;
1641 msg.message = message;
1642 msg.flags = sent|wparam|lparam;
1643 if (defwndproc_counter) msg.flags |= defwinproc;
1644 msg.wParam = wParam;
1645 msg.lParam = lParam;
1646 add_message(&msg);
1649 defwndproc_counter++;
1650 ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
1651 defwndproc_counter--;
1653 return ret;
1656 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1658 static long defwndproc_counter = 0;
1659 LRESULT ret;
1660 struct message msg;
1662 /* do not log painting messages */
1663 if (message != WM_PAINT &&
1664 message != WM_ERASEBKGND &&
1665 message != WM_NCPAINT &&
1666 message != WM_GETTEXT)
1668 trace("mdi frame: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1670 switch (message)
1672 case WM_WINDOWPOSCHANGING:
1673 case WM_WINDOWPOSCHANGED:
1675 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
1677 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
1678 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
1679 winpos->hwnd, winpos->hwndInsertAfter,
1680 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
1682 /* Log only documented flags, win2k uses 0x1000 and 0x2000
1683 * in the high word for internal purposes
1685 wParam = winpos->flags & 0xffff;
1686 break;
1690 msg.message = message;
1691 msg.flags = sent|wparam|lparam;
1692 if (defwndproc_counter) msg.flags |= defwinproc;
1693 msg.wParam = wParam;
1694 msg.lParam = lParam;
1695 add_message(&msg);
1698 defwndproc_counter++;
1699 ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
1700 defwndproc_counter--;
1702 return ret;
1705 static BOOL mdi_RegisterWindowClasses(void)
1707 WNDCLASSA cls;
1709 cls.style = 0;
1710 cls.lpfnWndProc = mdi_frame_wnd_proc;
1711 cls.cbClsExtra = 0;
1712 cls.cbWndExtra = 0;
1713 cls.hInstance = GetModuleHandleA(0);
1714 cls.hIcon = 0;
1715 cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
1716 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
1717 cls.lpszMenuName = NULL;
1718 cls.lpszClassName = "MDI_frame_class";
1719 if (!RegisterClassA(&cls)) return FALSE;
1721 cls.lpfnWndProc = mdi_child_wnd_proc;
1722 cls.lpszClassName = "MDI_child_class";
1723 if (!RegisterClassA(&cls)) return FALSE;
1725 if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
1726 old_mdi_client_proc = cls.lpfnWndProc;
1727 cls.hInstance = GetModuleHandleA(0);
1728 cls.lpfnWndProc = mdi_client_hook_proc;
1729 cls.lpszClassName = "MDI_client_class";
1730 if (!RegisterClassA(&cls)) assert(0);
1732 return TRUE;
1735 static void test_mdi_messages(void)
1737 MDICREATESTRUCTA mdi_cs;
1738 CLIENTCREATESTRUCT client_cs;
1739 HWND mdi_frame, mdi_child, mdi_child2, active_child;
1740 BOOL zoomed;
1741 HMENU hMenu = CreateMenu();
1743 assert(mdi_RegisterWindowClasses());
1745 flush_sequence();
1747 trace("creating MDI frame window\n");
1748 mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
1749 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
1750 WS_MAXIMIZEBOX | WS_VISIBLE,
1751 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
1752 GetDesktopWindow(), hMenu,
1753 GetModuleHandleA(0), NULL);
1754 assert(mdi_frame);
1755 ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", TRUE);
1757 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1758 ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
1760 trace("creating MDI client window\n");
1761 client_cs.hWindowMenu = 0;
1762 client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
1763 mdi_client = CreateWindowExA(0, "MDI_client_class",
1764 NULL,
1765 WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
1766 0, 0, 0, 0,
1767 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
1768 assert(mdi_client);
1769 ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
1771 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1772 ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
1774 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1775 ok(!active_child, "wrong active MDI child %p\n", active_child);
1776 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
1778 SetFocus(0);
1779 flush_sequence();
1781 trace("creating visible MDI child window\n");
1782 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
1783 WS_CHILD | WS_VISIBLE,
1784 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
1785 mdi_client, 0, GetModuleHandleA(0), NULL);
1786 assert(mdi_child);
1787 ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", TRUE);
1789 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
1790 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
1792 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1793 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
1795 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1796 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
1797 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
1798 flush_sequence();
1800 DestroyWindow(mdi_child);
1801 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
1803 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1804 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1806 /* Win2k: MDI client still returns a just destroyed child as active
1807 * Win9x: MDI client returns 0
1809 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1810 ok(active_child == mdi_child || /* win2k */
1811 !active_child, /* win9x */
1812 "wrong active MDI child %p\n", active_child);
1813 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
1815 flush_sequence();
1817 trace("creating invisible MDI child window\n");
1818 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
1819 WS_CHILD,
1820 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
1821 mdi_client, 0, GetModuleHandleA(0), NULL);
1822 assert(mdi_child2);
1823 ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
1825 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
1826 ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
1828 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1829 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1831 /* Win2k: MDI client still returns a just destroyed child as active
1832 * Win9x: MDI client returns mdi_child2
1834 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1835 ok(active_child == mdi_child || /* win2k */
1836 active_child == mdi_child2, /* win9x */
1837 "wrong active MDI child %p\n", active_child);
1838 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
1839 flush_sequence();
1841 ShowWindow(mdi_child2, SW_MAXIMIZE);
1842 ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", TRUE);
1844 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
1845 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
1847 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1848 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
1849 ok(zoomed, "wrong zoomed state %d\n", zoomed);
1850 flush_sequence();
1852 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1853 ok(GetFocus() == mdi_child2 || /* win2k */
1854 GetFocus() == 0, /* win9x */
1855 "wrong focus window %p\n", GetFocus());
1857 SetFocus(0);
1858 flush_sequence();
1860 ShowWindow(mdi_child2, SW_HIDE);
1861 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
1863 ShowWindow(mdi_child2, SW_RESTORE);
1864 ok_sequence(WmRestoreMDIchildInisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", TRUE);
1865 flush_sequence();
1867 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
1868 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
1870 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1871 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
1872 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
1873 flush_sequence();
1875 SetFocus(0);
1876 flush_sequence();
1878 ShowWindow(mdi_child2, SW_HIDE);
1879 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
1881 ShowWindow(mdi_child2, SW_SHOW);
1882 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", TRUE);
1884 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1885 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1887 ShowWindow(mdi_child2, SW_MAXIMIZE);
1888 ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", TRUE);
1890 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1891 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1893 ShowWindow(mdi_child2, SW_RESTORE);
1894 ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):MDI child", TRUE);
1896 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1897 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1899 SetFocus(0);
1900 flush_sequence();
1902 ShowWindow(mdi_child2, SW_HIDE);
1903 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
1905 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1906 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1908 DestroyWindow(mdi_child2);
1909 ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", TRUE);
1911 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1912 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1914 /* test for maximized MDI children */
1915 trace("creating maximized visible MDI child window 1\n");
1916 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
1917 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
1918 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
1919 mdi_client, 0, GetModuleHandleA(0), NULL);
1920 assert(mdi_child);
1921 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
1922 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
1924 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1925 ok(GetFocus() == mdi_child || /* win2k */
1926 GetFocus() == 0, /* win9x */
1927 "wrong focus window %p\n", GetFocus());
1929 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1930 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
1931 ok(zoomed, "wrong zoomed state %d\n", zoomed);
1932 flush_sequence();
1934 trace("creating maximized visible MDI child window 2\n");
1935 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
1936 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
1937 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
1938 mdi_client, 0, GetModuleHandleA(0), NULL);
1939 assert(mdi_child2);
1940 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
1941 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
1942 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
1944 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1945 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
1947 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1948 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
1949 ok(zoomed, "wrong zoomed state %d\n", zoomed);
1950 flush_sequence();
1952 trace("destroying maximized visible MDI child window 2\n");
1953 DestroyWindow(mdi_child2);
1954 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
1956 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
1958 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1959 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1961 /* Win2k: MDI client still returns a just destroyed child as active
1962 * Win9x: MDI client returns 0
1964 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1965 ok(active_child == mdi_child2 || /* win2k */
1966 !active_child, /* win9x */
1967 "wrong active MDI child %p\n", active_child);
1968 flush_sequence();
1970 ShowWindow(mdi_child, SW_MAXIMIZE);
1971 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
1972 flush_sequence();
1974 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1975 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
1977 trace("re-creating maximized visible MDI child window 2\n");
1978 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
1979 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
1980 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
1981 mdi_client, 0, GetModuleHandleA(0), NULL);
1982 assert(mdi_child2);
1983 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
1984 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
1985 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
1987 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1988 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
1990 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1991 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
1992 ok(zoomed, "wrong zoomed state %d\n", zoomed);
1993 flush_sequence();
1995 SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
1996 ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
1997 ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
1999 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
2000 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2001 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
2003 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2004 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
2005 ok(zoomed, "wrong zoomed state %d\n", zoomed);
2006 flush_sequence();
2008 DestroyWindow(mdi_child);
2009 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
2011 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2012 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2014 /* Win2k: MDI client still returns a just destroyed child as active
2015 * Win9x: MDI client returns 0
2017 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2018 ok(active_child == mdi_child || /* win2k */
2019 !active_child, /* win9x */
2020 "wrong active MDI child %p\n", active_child);
2021 flush_sequence();
2022 /* end of test for maximized MDI children */
2024 mdi_cs.szClass = "MDI_child_Class";
2025 mdi_cs.szTitle = "MDI child";
2026 mdi_cs.hOwner = GetModuleHandleA(0);
2027 mdi_cs.x = 0;
2028 mdi_cs.y = 0;
2029 mdi_cs.cx = CW_USEDEFAULT;
2030 mdi_cs.cy = CW_USEDEFAULT;
2031 mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
2032 mdi_cs.lParam = 0;
2033 mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
2034 ok(mdi_child != 0, "MDI child creation failed\n");
2035 ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
2037 ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
2039 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2040 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
2042 ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
2043 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2044 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
2046 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2047 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
2048 ok(zoomed, "wrong zoomed state %d\n", zoomed);
2049 flush_sequence();
2051 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
2052 ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
2054 ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
2055 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2056 ok(!active_child, "wrong active MDI child %p\n", active_child);
2058 SetFocus(0);
2059 flush_sequence();
2061 DestroyWindow(mdi_client);
2062 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
2064 DestroyWindow(mdi_frame);
2065 ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
2067 /************************* End of MDI test **********************************/
2069 static void test_WM_SETREDRAW(HWND hwnd)
2071 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
2073 flush_sequence();
2075 SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
2076 ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
2078 ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
2079 ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
2081 flush_sequence();
2082 SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
2083 ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
2085 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
2086 ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
2088 /* restore original WS_VISIBLE state */
2089 SetWindowLongA(hwnd, GWL_STYLE, style);
2091 flush_sequence();
2094 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2096 struct message msg;
2098 trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2100 msg.message = message;
2101 msg.flags = sent|wparam|lparam;
2102 msg.wParam = wParam;
2103 msg.lParam = lParam;
2104 add_message(&msg);
2106 if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
2107 if (message == WM_TIMER) EndDialog( hwnd, 0 );
2108 return 0;
2111 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
2113 DWORD style, exstyle;
2114 INT xmin, xmax;
2116 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
2117 style = GetWindowLongA(hwnd, GWL_STYLE);
2118 /* do not be confused by WS_DLGFRAME set */
2119 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
2121 if (clear) ok(style & clear, "style %08lx should be set\n", clear);
2122 if (set) ok(!(style & set), "style %08lx should not be set\n", set);
2124 ok(SetScrollRange(hwnd, ctl, min, max, FALSE), "SetScrollRange(%d) error %ld\n", ctl, GetLastError());
2125 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
2126 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
2127 else
2128 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", TRUE);
2130 style = GetWindowLongA(hwnd, GWL_STYLE);
2131 if (set) ok(style & set, "style %08lx should be set\n", set);
2132 if (clear) ok(!(style & clear), "style %08lx should not be set\n", clear);
2134 /* a subsequent call should do nothing */
2135 ok(SetScrollRange(hwnd, ctl, min, max, FALSE), "SetScrollRange(%d) error %ld\n", ctl, GetLastError());
2136 ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
2138 xmin = 0xdeadbeef;
2139 xmax = 0xdeadbeef;
2140 trace("Ignore GetScrollRange error below if you are on Win9x\n");
2141 ok(GetScrollRange(hwnd, ctl, &xmin, &xmax), "GetScrollRange(%d) error %ld\n", ctl, GetLastError());
2142 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT)", FALSE);
2143 ok(xmin == min, "unexpected min scroll value %d\n", xmin);
2144 ok(xmax == max, "unexpected max scroll value %d\n", xmax);
2147 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
2149 DWORD style, exstyle;
2150 SCROLLINFO si;
2152 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
2153 style = GetWindowLongA(hwnd, GWL_STYLE);
2154 /* do not be confused by WS_DLGFRAME set */
2155 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
2157 if (clear) ok(style & clear, "style %08lx should be set\n", clear);
2158 if (set) ok(!(style & set), "style %08lx should not be set\n", set);
2160 si.cbSize = sizeof(si);
2161 si.fMask = SIF_RANGE;
2162 si.nMin = min;
2163 si.nMax = max;
2164 SetScrollInfo(hwnd, ctl, &si, TRUE);
2165 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
2166 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
2167 else
2168 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", TRUE);
2170 style = GetWindowLongA(hwnd, GWL_STYLE);
2171 if (set) ok(style & set, "style %08lx should be set\n", set);
2172 if (clear) ok(!(style & clear), "style %08lx should not be set\n", clear);
2174 /* a subsequent call should do nothing */
2175 SetScrollInfo(hwnd, ctl, &si, TRUE);
2176 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
2178 si.fMask = SIF_PAGE;
2179 si.nPage = 5;
2180 SetScrollInfo(hwnd, ctl, &si, FALSE);
2181 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
2183 si.fMask = SIF_POS;
2184 si.nPos = max - 1;
2185 SetScrollInfo(hwnd, ctl, &si, FALSE);
2186 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
2188 si.fMask = SIF_RANGE;
2189 si.nMin = 0xdeadbeef;
2190 si.nMax = 0xdeadbeef;
2191 ok(GetScrollInfo(hwnd, ctl, &si), "GetScrollInfo error %ld\n", GetLastError());
2192 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT)", FALSE);
2193 ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
2194 ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
2197 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
2198 static void test_scroll_messages(HWND hwnd)
2200 SCROLLINFO si;
2201 INT min, max;
2203 min = 0xdeadbeef;
2204 max = 0xdeadbeef;
2205 ok(GetScrollRange(hwnd, SB_CTL, &min, &max), "GetScrollRange error %ld\n", GetLastError());
2206 if (sequence->message != WmGetScrollRangeSeq[0].message)
2207 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
2208 /* values of min and max are undefined */
2209 flush_sequence();
2211 ok(SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE), "SetScrollRange error %ld\n", GetLastError());
2212 if (sequence->message != WmSetScrollRangeSeq[0].message)
2213 trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
2214 flush_sequence();
2216 min = 0xdeadbeef;
2217 max = 0xdeadbeef;
2218 ok(GetScrollRange(hwnd, SB_CTL, &min, &max), "GetScrollRange error %ld\n", GetLastError());
2219 if (sequence->message != WmGetScrollRangeSeq[0].message)
2220 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
2221 /* values of min and max are undefined */
2222 flush_sequence();
2224 si.cbSize = sizeof(si);
2225 si.fMask = SIF_RANGE;
2226 si.nMin = 20;
2227 si.nMax = 160;
2228 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
2229 if (sequence->message != WmSetScrollRangeSeq[0].message)
2230 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
2231 flush_sequence();
2233 si.fMask = SIF_PAGE;
2234 si.nPage = 10;
2235 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
2236 if (sequence->message != WmSetScrollRangeSeq[0].message)
2237 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
2238 flush_sequence();
2240 si.fMask = SIF_POS;
2241 si.nPos = 20;
2242 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
2243 if (sequence->message != WmSetScrollRangeSeq[0].message)
2244 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
2245 flush_sequence();
2247 si.fMask = SIF_RANGE;
2248 si.nMin = 0xdeadbeef;
2249 si.nMax = 0xdeadbeef;
2250 ok(GetScrollInfo(hwnd, SB_CTL, &si), "GetScrollInfo error %ld\n", GetLastError());
2251 if (sequence->message != WmGetScrollInfoSeq[0].message)
2252 trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
2253 /* values of min and max are undefined */
2254 flush_sequence();
2256 /* set WS_HSCROLL */
2257 test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
2258 /* clear WS_HSCROLL */
2259 test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
2261 /* set WS_HSCROLL */
2262 test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
2263 /* clear WS_HSCROLL */
2264 test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
2266 /* set WS_VSCROLL */
2267 test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
2268 /* clear WS_VSCROLL */
2269 test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
2271 /* set WS_VSCROLL */
2272 test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
2273 /* clear WS_VSCROLL */
2274 test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
2277 /* test if we receive the right sequence of messages */
2278 static void test_messages(void)
2280 HWND hwnd, hparent, hchild;
2281 HWND hchild2, hbutton;
2282 HMENU hmenu;
2284 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
2285 100, 100, 200, 200, 0, 0, 0, NULL);
2286 ok (hwnd != 0, "Failed to create overlapped window\n");
2287 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
2289 /* test ShowWindow(SW_HIDE) on a newly created invisible window */
2290 ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
2291 ok_sequence(WmHideInvisibleOverlappedSeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
2293 /* test WM_SETREDRAW on a not visible top level window */
2294 test_WM_SETREDRAW(hwnd);
2296 SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
2297 ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
2298 ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
2300 ok(GetActiveWindow() == hwnd, "window should be active\n");
2301 ok(GetFocus() == hwnd, "window should have input focus\n");
2302 ShowWindow(hwnd, SW_HIDE);
2303 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", TRUE);
2305 ShowWindow(hwnd, SW_SHOW);
2306 ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
2308 ok(GetActiveWindow() == hwnd, "window should be active\n");
2309 ok(GetFocus() == hwnd, "window should have input focus\n");
2310 SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
2311 ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", TRUE);
2312 ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
2314 /* test WM_SETREDRAW on a visible top level window */
2315 ShowWindow(hwnd, SW_SHOW);
2316 test_WM_SETREDRAW(hwnd);
2318 trace("testing scroll APIs on a visible top level window %p\n", hwnd);
2319 test_scroll_messages(hwnd);
2321 DestroyWindow(hwnd);
2322 ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
2324 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
2325 100, 100, 200, 200, 0, 0, 0, NULL);
2326 ok (hparent != 0, "Failed to create parent window\n");
2327 flush_sequence();
2329 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
2330 0, 0, 10, 10, hparent, 0, 0, NULL);
2331 ok (hchild != 0, "Failed to create child window\n");
2332 ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", TRUE);
2333 DestroyWindow(hchild);
2334 flush_sequence();
2336 /* visible child window with a caption */
2337 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
2338 WS_CHILD | WS_VISIBLE | WS_CAPTION,
2339 0, 0, 10, 10, hparent, 0, 0, NULL);
2340 ok (hchild != 0, "Failed to create child window\n");
2341 ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
2343 trace("testing scroll APIs on a visible child window %p\n", hchild);
2344 test_scroll_messages(hchild);
2346 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
2347 ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
2349 DestroyWindow(hchild);
2350 flush_sequence();
2352 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
2353 0, 0, 10, 10, hparent, 0, 0, NULL);
2354 ok (hchild != 0, "Failed to create child window\n");
2355 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
2357 hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
2358 100, 100, 50, 50, hparent, 0, 0, NULL);
2359 ok (hchild2 != 0, "Failed to create child2 window\n");
2360 flush_sequence();
2362 hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
2363 0, 100, 50, 50, hchild, 0, 0, NULL);
2364 ok (hbutton != 0, "Failed to create button window\n");
2366 /* test WM_SETREDRAW on a not visible child window */
2367 test_WM_SETREDRAW(hchild);
2369 ShowWindow(hchild, SW_SHOW);
2370 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
2372 ShowWindow(hchild, SW_HIDE);
2373 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
2375 ShowWindow(hchild, SW_SHOW);
2376 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
2378 /* test WM_SETREDRAW on a visible child window */
2379 test_WM_SETREDRAW(hchild);
2381 MoveWindow(hchild, 10, 10, 20, 20, TRUE);
2382 ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
2384 ShowWindow(hchild, SW_HIDE);
2385 flush_sequence();
2386 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
2387 ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
2389 ShowWindow(hchild, SW_HIDE);
2390 flush_sequence();
2391 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
2392 ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
2394 /* DestroyWindow sequence below expects that a child has focus */
2395 SetFocus(hchild);
2396 flush_sequence();
2398 DestroyWindow(hchild);
2399 ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
2400 DestroyWindow(hchild2);
2401 DestroyWindow(hbutton);
2403 flush_sequence();
2404 hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
2405 0, 0, 100, 100, hparent, 0, 0, NULL);
2406 ok (hchild != 0, "Failed to create child popup window\n");
2407 ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
2408 DestroyWindow(hchild);
2410 /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
2411 flush_sequence();
2412 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
2413 0, 0, 100, 100, hparent, 0, 0, NULL);
2414 ok (hchild != 0, "Failed to create popup window\n");
2415 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
2416 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
2417 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
2418 flush_sequence();
2419 ShowWindow(hchild, SW_SHOW);
2420 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
2421 flush_sequence();
2422 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
2423 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
2424 flush_sequence();
2425 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
2426 ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
2427 DestroyWindow(hchild);
2429 /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
2430 * changes nothing in message sequences.
2432 flush_sequence();
2433 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
2434 0, 0, 100, 100, hparent, 0, 0, NULL);
2435 ok (hchild != 0, "Failed to create popup window\n");
2436 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
2437 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
2438 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
2439 flush_sequence();
2440 ShowWindow(hchild, SW_SHOW);
2441 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
2442 flush_sequence();
2443 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
2444 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
2445 DestroyWindow(hchild);
2447 flush_sequence();
2448 hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
2449 0, 0, 100, 100, hparent, 0, 0, NULL);
2450 ok(hwnd != 0, "Failed to create custom dialog window\n");
2451 ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
2453 trace("testing scroll APIs on a visible dialog %p\n", hwnd);
2454 test_scroll_messages(hwnd);
2456 flush_sequence();
2457 after_end_dialog = 1;
2458 EndDialog( hwnd, 0 );
2459 ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
2461 DestroyWindow(hwnd);
2462 after_end_dialog = 0;
2464 flush_sequence();
2465 DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
2466 ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
2468 /* test showing child with hidden parent */
2469 ShowWindow( hparent, SW_HIDE );
2470 flush_sequence();
2472 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
2473 0, 0, 10, 10, hparent, 0, 0, NULL);
2474 ok (hchild != 0, "Failed to create child window\n");
2475 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
2477 ShowWindow( hchild, SW_SHOW );
2478 ok_sequence(WmShowChildInvisibleParentSeq, "ShowWindow:show child with invisible parent", TRUE);
2479 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
2480 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
2482 ShowWindow( hchild, SW_HIDE );
2483 ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", TRUE);
2484 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
2485 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
2487 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
2488 ok_sequence(WmShowChildInvisibleParentSeq_2, "SetWindowPos:show child with invisible parent", TRUE);
2489 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
2490 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
2492 SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
2493 ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", TRUE);
2494 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
2495 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
2497 DestroyWindow(hchild);
2498 DestroyWindow(hparent);
2499 flush_sequence();
2501 /* Message sequence for SetMenu */
2502 ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a window without a menu\n");
2503 ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
2505 hmenu = CreateMenu();
2506 ok (hmenu != 0, "Failed to create menu\n");
2507 ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
2508 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
2509 100, 100, 200, 200, 0, hmenu, 0, NULL);
2510 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
2511 ok (SetMenu(hwnd, 0), "SetMenu\n");
2512 ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
2513 ok (SetMenu(hwnd, 0), "SetMenu\n");
2514 ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
2515 ShowWindow(hwnd, SW_SHOW);
2516 flush_sequence();
2517 ok (SetMenu(hwnd, 0), "SetMenu\n");
2518 ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", TRUE);
2519 ok (SetMenu(hwnd, hmenu), "SetMenu\n");
2520 ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", TRUE);
2522 ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
2523 ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", TRUE);
2525 DestroyWindow(hwnd);
2526 flush_sequence();
2528 /* Message sequence for EnableWindow */
2529 hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
2530 100, 100, 200, 200, 0, 0, 0, NULL);
2531 ok (hparent != 0, "Failed to create parent window\n");
2532 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
2533 0, 0, 10, 10, hparent, 0, 0, NULL);
2534 ok (hchild != 0, "Failed to create child window\n");
2536 SetFocus(hchild);
2537 flush_sequence();
2539 EnableWindow(hparent, FALSE);
2540 ok_sequence(WmEnableWindowSeq, "EnableWindow", FALSE);
2542 DestroyWindow(hchild);
2543 DestroyWindow(hparent);
2544 flush_sequence();
2547 /****************** button message test *************************/
2548 static const struct message WmSetFocusButtonSeq[] =
2550 { HCBT_SETFOCUS, hook },
2551 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2552 { WM_SETFOCUS, sent|wparam, 0 },
2553 { WM_CTLCOLORBTN, sent|defwinproc },
2554 { 0 }
2556 static const struct message WmKillFocusButtonSeq[] =
2558 { HCBT_SETFOCUS, hook },
2559 { WM_KILLFOCUS, sent|wparam, 0 },
2560 { WM_CTLCOLORBTN, sent|defwinproc },
2561 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2562 { 0 }
2564 static const struct message WmSetFocusStaticSeq[] =
2566 { HCBT_SETFOCUS, hook },
2567 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2568 { WM_SETFOCUS, sent|wparam, 0 },
2569 { WM_CTLCOLORSTATIC, sent|defwinproc },
2570 { 0 }
2572 static const struct message WmKillFocusStaticSeq[] =
2574 { HCBT_SETFOCUS, hook },
2575 { WM_KILLFOCUS, sent|wparam, 0 },
2576 { WM_CTLCOLORSTATIC, sent|defwinproc },
2577 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2578 { 0 }
2580 static const struct message WmLButtonDownSeq[] =
2582 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
2583 { HCBT_SETFOCUS, hook },
2584 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2585 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
2586 { WM_CTLCOLORBTN, sent|defwinproc },
2587 { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
2588 { WM_CTLCOLORBTN, sent|defwinproc },
2589 { 0 }
2591 static const struct message WmLButtonUpSeq[] =
2593 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
2594 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
2595 { WM_CTLCOLORBTN, sent|defwinproc },
2596 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
2597 { 0 }
2600 static WNDPROC old_button_proc;
2602 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2604 static long defwndproc_counter = 0;
2605 LRESULT ret;
2606 struct message msg;
2608 trace("button: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2610 msg.message = message;
2611 msg.flags = sent|wparam|lparam;
2612 if (defwndproc_counter) msg.flags |= defwinproc;
2613 msg.wParam = wParam;
2614 msg.lParam = lParam;
2615 add_message(&msg);
2617 if (message == BM_SETSTATE)
2618 ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
2620 defwndproc_counter++;
2621 ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
2622 defwndproc_counter--;
2624 return ret;
2627 static void subclass_button(void)
2629 WNDCLASSA cls;
2631 if (!GetClassInfoA(0, "button", &cls)) assert(0);
2633 old_button_proc = cls.lpfnWndProc;
2635 cls.hInstance = GetModuleHandle(0);
2636 cls.lpfnWndProc = button_hook_proc;
2637 cls.lpszClassName = "my_button_class";
2638 if (!RegisterClassA(&cls)) assert(0);
2641 static void test_button_messages(void)
2643 static const struct
2645 DWORD style;
2646 const struct message *setfocus;
2647 const struct message *killfocus;
2648 } button[] = {
2649 { BS_PUSHBUTTON, WmSetFocusButtonSeq, WmKillFocusButtonSeq },
2650 { BS_DEFPUSHBUTTON, WmSetFocusButtonSeq, WmKillFocusButtonSeq },
2651 { BS_CHECKBOX, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2652 { BS_AUTOCHECKBOX, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2653 { BS_RADIOBUTTON, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2654 { BS_3STATE, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2655 { BS_AUTO3STATE, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2656 { BS_GROUPBOX, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2657 { BS_USERBUTTON, WmSetFocusButtonSeq, WmKillFocusButtonSeq },
2658 { BS_AUTORADIOBUTTON, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2659 { BS_OWNERDRAW, WmSetFocusButtonSeq, WmKillFocusButtonSeq }
2661 unsigned int i;
2662 HWND hwnd;
2664 subclass_button();
2666 for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
2668 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP,
2669 0, 0, 50, 14, 0, 0, 0, NULL);
2670 ok(hwnd != 0, "Failed to create button window\n");
2672 ShowWindow(hwnd, SW_SHOW);
2673 UpdateWindow(hwnd);
2674 SetFocus(0);
2675 flush_sequence();
2677 trace("button style %08lx\n", button[i].style);
2678 SetFocus(hwnd);
2679 ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
2681 SetFocus(0);
2682 ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
2684 DestroyWindow(hwnd);
2687 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP | WS_VISIBLE,
2688 0, 0, 50, 14, 0, 0, 0, NULL);
2689 ok(hwnd != 0, "Failed to create button window\n");
2691 SetFocus(0);
2692 flush_sequence();
2694 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
2695 ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
2697 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
2698 ok_sequence(WmLButtonUpSeq, "WM_LBUTTONDOWN on a button", FALSE);
2699 DestroyWindow(hwnd);
2702 /************* painting message test ********************/
2704 static void dump_region(HRGN hrgn)
2706 DWORD i, size;
2707 RGNDATA *data = NULL;
2708 RECT *rect;
2710 if (!hrgn)
2712 printf( "null region\n" );
2713 return;
2715 if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
2716 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
2717 GetRegionData( hrgn, size, data );
2718 printf("%ld rects:", data->rdh.nCount );
2719 for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
2720 printf( " (%ld,%ld)-(%ld,%ld)", rect->left, rect->top, rect->right, rect->bottom );
2721 printf("\n");
2722 HeapFree( GetProcessHeap(), 0, data );
2725 static void check_update_rgn( HWND hwnd, HRGN hrgn )
2727 INT ret;
2728 RECT r1, r2;
2729 HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
2730 HRGN update = CreateRectRgn( 0, 0, 0, 0 );
2732 ret = GetUpdateRgn( hwnd, update, FALSE );
2733 ok( ret != ERROR, "GetUpdateRgn failed\n" );
2734 if (ret == NULLREGION)
2736 ok( !hrgn, "Update region shouldn't be empty\n" );
2738 else
2740 if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
2742 ok( 0, "Regions are different\n" );
2743 if (winetest_debug > 0)
2745 printf( "Update region: " );
2746 dump_region( update );
2747 printf( "Wanted region: " );
2748 dump_region( hrgn );
2752 GetRgnBox( update, &r1 );
2753 GetUpdateRect( hwnd, &r2, FALSE );
2754 ok( r1.left == r2.left && r1.top == r2.top && r1.right == r2.right && r1.bottom == r2.bottom,
2755 "Rectangles are different: %ld,%ld-%ld,%ld / %ld,%ld-%ld,%ld\n",
2756 r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom );
2758 DeleteObject( tmp );
2759 DeleteObject( update );
2762 static const struct message WmInvalidateRgn[] = {
2763 { WM_NCPAINT, sent },
2764 { WM_GETTEXT, sent|defwinproc|optional },
2765 { 0 }
2768 static const struct message WmInvalidateFull[] = {
2769 { WM_NCPAINT, sent|wparam, 1 },
2770 { WM_GETTEXT, sent|defwinproc|optional },
2771 { 0 }
2774 static const struct message WmInvalidateErase[] = {
2775 { WM_NCPAINT, sent|wparam, 1 },
2776 { WM_GETTEXT, sent|defwinproc|optional },
2777 { WM_ERASEBKGND, sent },
2778 { 0 }
2781 static const struct message WmInvalidatePaint[] = {
2782 { WM_PAINT, sent },
2783 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
2784 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
2785 { 0 }
2788 static const struct message WmInvalidateErasePaint[] = {
2789 { WM_PAINT, sent },
2790 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
2791 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
2792 { WM_ERASEBKGND, sent|beginpaint },
2793 { 0 }
2796 static const struct message WmErase[] = {
2797 { WM_ERASEBKGND, sent },
2798 { 0 }
2801 static const struct message WmPaint[] = {
2802 { WM_PAINT, sent },
2803 { 0 }
2806 static void test_paint_messages(void)
2808 RECT rect;
2809 MSG msg;
2810 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
2811 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
2812 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
2813 100, 100, 200, 200, 0, 0, 0, NULL);
2814 ok (hwnd != 0, "Failed to create overlapped window\n");
2816 ShowWindow( hwnd, SW_SHOW );
2817 UpdateWindow( hwnd );
2818 check_update_rgn( hwnd, 0 );
2819 SetRectRgn( hrgn, 10, 10, 20, 20 );
2820 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
2821 check_update_rgn( hwnd, hrgn );
2822 SetRectRgn( hrgn2, 20, 20, 30, 30 );
2823 RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
2824 CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
2825 check_update_rgn( hwnd, hrgn );
2826 /* validate everything */
2827 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
2828 check_update_rgn( hwnd, 0 );
2829 /* now with frame */
2830 SetRectRgn( hrgn, -5, -5, 20, 20 );
2832 flush_sequence();
2833 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
2834 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
2836 SetRectRgn( hrgn, 0, 0, 20, 20 ); /* GetUpdateRgn clips to client area */
2837 check_update_rgn( hwnd, hrgn );
2839 flush_sequence();
2840 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
2841 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
2843 flush_sequence();
2844 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
2845 ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
2847 GetClientRect( hwnd, &rect );
2848 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
2849 check_update_rgn( hwnd, hrgn );
2851 flush_sequence();
2852 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
2853 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
2855 flush_sequence();
2856 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
2857 ok_sequence( WmInvalidatePaint, "InvalidatePaint", TRUE );
2858 check_update_rgn( hwnd, 0 );
2860 flush_sequence();
2861 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
2862 ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
2863 check_update_rgn( hwnd, 0 );
2865 flush_sequence();
2866 SetRectRgn( hrgn, 0, 0, 100, 100 );
2867 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
2868 SetRectRgn( hrgn, 0, 0, 50, 100 );
2869 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
2870 SetRectRgn( hrgn, 50, 0, 100, 100 );
2871 check_update_rgn( hwnd, hrgn );
2872 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
2873 ok_sequence( WmEmptySeq, "EmptySeq", FALSE ); /* must not generate messages, everything is valid */
2874 check_update_rgn( hwnd, 0 );
2876 flush_sequence();
2877 SetRectRgn( hrgn, 0, 0, 100, 100 );
2878 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
2879 SetRectRgn( hrgn, 0, 0, 100, 50 );
2880 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
2881 ok_sequence( WmErase, "Erase", FALSE );
2882 SetRectRgn( hrgn, 0, 50, 100, 100 );
2883 check_update_rgn( hwnd, hrgn );
2885 flush_sequence();
2886 SetRectRgn( hrgn, 0, 0, 100, 100 );
2887 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
2888 SetRectRgn( hrgn, 0, 0, 50, 50 );
2889 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
2890 ok_sequence( WmPaint, "Paint", FALSE );
2892 flush_sequence();
2893 SetRectRgn( hrgn, -4, -4, -2, -2 );
2894 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
2895 SetRectRgn( hrgn, -4, -4, -3, -3 );
2896 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
2897 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
2899 flush_sequence();
2900 SetRectRgn( hrgn, -4, -4, -2, -2 );
2901 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
2902 SetRectRgn( hrgn, -4, -4, -3, -3 );
2903 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
2904 SetRectRgn( hrgn, 0, 0, 1, 1 );
2905 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
2906 ok_sequence( WmPaint, "Paint", TRUE );
2908 flush_sequence();
2909 SetRectRgn( hrgn, -4, -4, -1, -1 );
2910 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
2911 RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
2912 /* make sure no WM_PAINT was generated */
2913 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
2914 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
2916 flush_sequence();
2917 SetRectRgn( hrgn, -4, -4, -1, -1 );
2918 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
2919 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
2921 if (msg.hwnd == hwnd && msg.message == WM_PAINT)
2923 /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
2924 INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
2925 ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
2926 ret = GetUpdateRect( hwnd, &rect, FALSE );
2927 ok( ret, "Invalid GetUpdateRect result %d\n", ret );
2928 /* this will send WM_NCPAINT and validate the non client area */
2929 ret = GetUpdateRect( hwnd, &rect, TRUE );
2930 ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
2932 else DispatchMessage( &msg );
2934 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
2936 DeleteObject( hrgn );
2937 DeleteObject( hrgn2 );
2938 DestroyWindow( hwnd );
2941 struct wnd_event
2943 HWND hwnd;
2944 HANDLE event;
2947 static DWORD WINAPI thread_proc(void *param)
2949 MSG msg;
2950 struct wnd_event *wnd_event = (struct wnd_event *)param;
2952 wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
2953 100, 100, 200, 200, 0, 0, 0, NULL);
2954 ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
2956 SetEvent(wnd_event->event);
2958 while (GetMessage(&msg, 0, 0, 0))
2960 TranslateMessage(&msg);
2961 DispatchMessage(&msg);
2964 return 0;
2967 static void test_interthread_messages(void)
2969 HANDLE hThread;
2970 DWORD tid;
2971 WNDPROC proc;
2972 MSG msg;
2973 char buf[256];
2974 int len, expected_len;
2975 struct wnd_event wnd_event;
2977 wnd_event.event = CreateEventW(NULL, 0, 0, NULL);
2978 if (!wnd_event.event)
2980 trace("skipping interthread message test under win9x\n");
2981 return;
2984 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
2985 ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError());
2987 ok(WaitForSingleObject(wnd_event.event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2989 CloseHandle(wnd_event.event);
2991 SetLastError(0xdeadbeef);
2992 ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeded\n");
2993 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error code %ld\n", GetLastError());
2995 proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
2996 ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %ld\n", GetLastError());
2998 expected_len = lstrlenA("window caption text");
2999 memset(buf, 0, sizeof(buf));
3000 SetLastError(0xdeadbeef);
3001 len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
3002 ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %ld, len %d, expected len %d\n", GetLastError(), len, expected_len);
3003 ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
3005 msg.hwnd = wnd_event.hwnd;
3006 msg.message = WM_GETTEXT;
3007 msg.wParam = sizeof(buf);
3008 msg.lParam = (LPARAM)buf;
3009 memset(buf, 0, sizeof(buf));
3010 SetLastError(0xdeadbeef);
3011 len = DispatchMessageA(&msg);
3012 ok(!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3013 "DispatchMessageA(WM_GETTEXT) succeded on another thread window: ret %d, error %ld\n", len, GetLastError());
3015 /* the following test causes an exception in user.exe under win9x */
3016 msg.hwnd = wnd_event.hwnd;
3017 msg.message = WM_TIMER;
3018 msg.wParam = 0;
3019 msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
3020 SetLastError(0xdeadbeef);
3021 len = DispatchMessageA(&msg);
3022 ok(!len && GetLastError() == 0xdeadbeef,
3023 "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %ld\n", len, GetLastError());
3025 ok(PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0), "PostMessageA(WM_QUIT) error %ld\n", GetLastError());
3027 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
3028 CloseHandle(hThread);
3032 static const struct message WmVkN[] = {
3033 { WM_KEYDOWN, wparam|lparam, VK_N, 1 },
3034 { WM_KEYDOWN, sent|wparam|lparam, VK_N, 1 },
3035 { WM_CHAR, wparam|lparam, 'n', 1 },
3036 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
3037 { WM_KEYUP, wparam|lparam, VK_N, 0xc0000001 },
3038 { WM_KEYUP, sent|wparam|lparam, VK_N, 0xc0000001 },
3039 { 0 }
3041 static const struct message WmShiftVkN[] = {
3042 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
3043 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
3044 { WM_KEYDOWN, wparam|lparam, VK_N, 1 },
3045 { WM_KEYDOWN, sent|wparam|lparam, VK_N, 1 },
3046 { WM_CHAR, wparam|lparam, 'N', 1 },
3047 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
3048 { WM_KEYUP, wparam|lparam, VK_N, 0xc0000001 },
3049 { WM_KEYUP, sent|wparam|lparam, VK_N, 0xc0000001 },
3050 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
3051 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
3052 { 0 }
3054 static const struct message WmCtrlVkN[] = {
3055 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
3056 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
3057 { WM_KEYDOWN, wparam|lparam, VK_N, 1 },
3058 { WM_KEYDOWN, sent|wparam|lparam, VK_N, 1 },
3059 { WM_CHAR, wparam|lparam, 0x000e, 1 },
3060 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
3061 { WM_KEYUP, wparam|lparam, VK_N, 0xc0000001 },
3062 { WM_KEYUP, sent|wparam|lparam, VK_N, 0xc0000001 },
3063 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
3064 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
3065 { 0 }
3067 static const struct message WmCtrlVkN_2[] = {
3068 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
3069 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
3070 { WM_KEYDOWN, wparam|lparam, VK_N, 1 },
3071 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
3072 { WM_KEYUP, wparam|lparam, VK_N, 0xc0000001 },
3073 { WM_KEYUP, sent|wparam|lparam, VK_N, 0xc0000001 },
3074 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
3075 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
3076 { 0 }
3078 static const struct message WmAltVkN[] = {
3079 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
3080 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
3081 { WM_SYSKEYDOWN, wparam|lparam, VK_N, 0x20000001 },
3082 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_N, 0x20000001 },
3083 { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
3084 { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
3085 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
3086 { HCBT_SYSCOMMAND, hook },
3087 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
3088 { WM_SETCURSOR, sent|defwinproc },
3089 { WM_INITMENU, sent|defwinproc },
3090 { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
3091 { WM_CAPTURECHANGED, sent|defwinproc },
3092 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
3093 { WM_EXITMENULOOP, sent|defwinproc },
3094 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
3095 { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
3096 { WM_SYSKEYUP, wparam|lparam, VK_N, 0xe0000001 },
3097 { WM_SYSKEYUP, sent|wparam|lparam, VK_N, 0xe0000001 },
3098 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
3099 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
3100 { 0 }
3102 static const struct message WmAltVkN_2[] = {
3103 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
3104 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
3105 { WM_SYSKEYDOWN, wparam|lparam, VK_N, 0x20000001 },
3106 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
3107 { WM_SYSKEYUP, wparam|lparam, VK_N, 0xe0000001 },
3108 { WM_SYSKEYUP, sent|wparam|lparam, VK_N, 0xe0000001 },
3109 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
3110 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
3111 { 0 }
3113 static const struct message WmCtrlAltVkN[] = {
3114 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
3115 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
3116 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
3117 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
3118 { WM_KEYDOWN, wparam|lparam, VK_N, 0x20000001 },
3119 { WM_KEYDOWN, sent|wparam|lparam, VK_N, 0x20000001 },
3120 { WM_KEYUP, wparam|lparam, VK_N, 0xe0000001 },
3121 { WM_KEYUP, sent|wparam|lparam, VK_N, 0xe0000001 },
3122 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
3123 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
3124 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
3125 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
3126 { 0 }
3129 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
3131 MSG msg;
3133 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
3135 struct message log_msg;
3137 trace("accel: %p, %04x, %08x, %08lx\n", msg.hwnd, msg.message, msg.wParam, msg.lParam);
3139 log_msg.message = msg.message;
3140 log_msg.flags = wparam|lparam;
3141 log_msg.wParam = msg.wParam;
3142 log_msg.lParam = msg.lParam;
3143 add_message(&log_msg);
3145 if (!TranslateAccelerator(hwnd, hAccel, &msg))
3147 TranslateMessage(&msg);
3148 DispatchMessage(&msg);
3153 static void test_accelerators(void)
3155 SHORT state;
3156 HACCEL hAccel;
3157 HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
3158 100, 100, 200, 200, 0, 0, 0, NULL);
3159 assert(hwnd != 0);
3161 SetFocus(hwnd);
3162 ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
3164 state = GetKeyState(VK_SHIFT);
3165 ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
3166 state = GetKeyState(VK_CAPITAL);
3167 ok(state == 0, "wrong CapsLock state %04x\n", state);
3169 hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(1));
3170 assert(hAccel != 0);
3172 trace("testing VK_N press/release\n");
3173 flush_sequence();
3174 keybd_event(VK_N, 0, 0, 0);
3175 keybd_event(VK_N, 0, KEYEVENTF_KEYUP, 0);
3176 pump_msg_loop(hwnd, hAccel);
3177 ok_sequence(WmVkN, "VK_N press/release", FALSE);
3179 trace("testing Shift+VK_N press/release\n");
3180 flush_sequence();
3181 keybd_event(VK_SHIFT, 0, 0, 0);
3182 keybd_event(VK_N, 0, 0, 0);
3183 keybd_event(VK_N, 0, KEYEVENTF_KEYUP, 0);
3184 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
3185 pump_msg_loop(hwnd, hAccel);
3186 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
3188 trace("testing Ctrl+VK_N press/release\n");
3189 flush_sequence();
3190 keybd_event(VK_CONTROL, 0, 0, 0);
3191 keybd_event(VK_N, 0, 0, 0);
3192 keybd_event(VK_N, 0, KEYEVENTF_KEYUP, 0);
3193 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
3194 pump_msg_loop(hwnd, hAccel);
3195 ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
3197 trace("testing Alt+VK_N press/release\n");
3198 flush_sequence();
3199 keybd_event(VK_MENU, 0, 0, 0);
3200 keybd_event(VK_N, 0, 0, 0);
3201 keybd_event(VK_N, 0, KEYEVENTF_KEYUP, 0);
3202 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
3203 pump_msg_loop(hwnd, hAccel);
3204 ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
3206 trace("testing Ctrl+Alt+VK_N press/release\n");
3207 flush_sequence();
3208 keybd_event(VK_CONTROL, 0, 0, 0);
3209 keybd_event(VK_MENU, 0, 0, 0);
3210 keybd_event(VK_N, 0, 0, 0);
3211 keybd_event(VK_N, 0, KEYEVENTF_KEYUP, 0);
3212 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
3213 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
3214 pump_msg_loop(hwnd, hAccel);
3215 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
3217 ok(DestroyAcceleratorTable(hAccel), "DestroyAcceleratorTable error %ld\n", GetLastError());
3219 hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(2));
3220 assert(hAccel != 0);
3222 trace("testing VK_N press/release\n");
3223 flush_sequence();
3224 keybd_event(VK_N, 0, 0, 0);
3225 keybd_event(VK_N, 0, KEYEVENTF_KEYUP, 0);
3226 pump_msg_loop(hwnd, hAccel);
3227 ok_sequence(WmVkN, "VK_N press/release", FALSE);
3229 trace("testing Shift+VK_N press/release\n");
3230 flush_sequence();
3231 keybd_event(VK_SHIFT, 0, 0, 0);
3232 keybd_event(VK_N, 0, 0, 0);
3233 keybd_event(VK_N, 0, KEYEVENTF_KEYUP, 0);
3234 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
3235 pump_msg_loop(hwnd, hAccel);
3236 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
3238 trace("testing Ctrl+VK_N press/release 2\n");
3239 flush_sequence();
3240 keybd_event(VK_CONTROL, 0, 0, 0);
3241 keybd_event(VK_N, 0, 0, 0);
3242 keybd_event(VK_N, 0, KEYEVENTF_KEYUP, 0);
3243 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
3244 pump_msg_loop(hwnd, hAccel);
3245 ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
3247 trace("testing Alt+VK_N press/release 2\n");
3248 flush_sequence();
3249 keybd_event(VK_MENU, 0, 0, 0);
3250 keybd_event(VK_N, 0, 0, 0);
3251 keybd_event(VK_N, 0, KEYEVENTF_KEYUP, 0);
3252 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
3253 pump_msg_loop(hwnd, hAccel);
3254 ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
3256 trace("testing Ctrl+Alt+VK_N press/release\n");
3257 flush_sequence();
3258 keybd_event(VK_CONTROL, 0, 0, 0);
3259 keybd_event(VK_MENU, 0, 0, 0);
3260 keybd_event(VK_N, 0, 0, 0);
3261 keybd_event(VK_N, 0, KEYEVENTF_KEYUP, 0);
3262 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
3263 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
3264 pump_msg_loop(hwnd, hAccel);
3265 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
3267 ok(DestroyAcceleratorTable(hAccel), "DestroyAcceleratorTable error %ld\n", GetLastError());
3269 DestroyWindow(hwnd);
3272 /************* window procedures ********************/
3274 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3276 static long defwndproc_counter = 0;
3277 static long beginpaint_counter = 0;
3278 LRESULT ret;
3279 struct message msg;
3281 trace("%p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
3283 switch (message)
3285 case WM_WINDOWPOSCHANGING:
3286 case WM_WINDOWPOSCHANGED:
3288 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
3290 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
3291 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
3292 winpos->hwnd, winpos->hwndInsertAfter,
3293 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
3295 /* Log only documented flags, win2k uses 0x1000 and 0x2000
3296 * in the high word for internal purposes
3298 wParam = winpos->flags & 0xffff;
3299 break;
3303 msg.message = message;
3304 msg.flags = sent|wparam|lparam;
3305 if (defwndproc_counter) msg.flags |= defwinproc;
3306 if (beginpaint_counter) msg.flags |= beginpaint;
3307 msg.wParam = wParam;
3308 msg.lParam = lParam;
3309 add_message(&msg);
3311 if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
3313 HWND parent = GetParent(hwnd);
3314 RECT rc;
3315 MINMAXINFO *minmax = (MINMAXINFO *)lParam;
3317 GetClientRect(parent, &rc);
3318 trace("parent %p client size = (%ld x %ld)\n", parent, rc.right, rc.bottom);
3320 trace("ptReserved = (%ld,%ld)\n"
3321 "ptMaxSize = (%ld,%ld)\n"
3322 "ptMaxPosition = (%ld,%ld)\n"
3323 "ptMinTrackSize = (%ld,%ld)\n"
3324 "ptMaxTrackSize = (%ld,%ld)\n",
3325 minmax->ptReserved.x, minmax->ptReserved.y,
3326 minmax->ptMaxSize.x, minmax->ptMaxSize.y,
3327 minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
3328 minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
3329 minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
3331 ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %ld != %ld\n",
3332 minmax->ptMaxSize.x, rc.right);
3333 ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %ld != %ld\n",
3334 minmax->ptMaxSize.y, rc.bottom);
3337 if (message == WM_PAINT)
3339 PAINTSTRUCT ps;
3340 beginpaint_counter++;
3341 BeginPaint( hwnd, &ps );
3342 beginpaint_counter--;
3343 EndPaint( hwnd, &ps );
3344 return 0;
3347 defwndproc_counter++;
3348 ret = DefWindowProcA(hwnd, message, wParam, lParam);
3349 defwndproc_counter--;
3351 return ret;
3354 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3356 static long defwndproc_counter = 0;
3357 LRESULT ret;
3358 struct message msg;
3360 trace("popup: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
3362 msg.message = message;
3363 msg.flags = sent|wparam|lparam;
3364 if (defwndproc_counter) msg.flags |= defwinproc;
3365 msg.wParam = wParam;
3366 msg.lParam = lParam;
3367 add_message(&msg);
3369 if (message == WM_CREATE)
3371 DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
3372 SetWindowLongA(hwnd, GWL_STYLE, style);
3375 defwndproc_counter++;
3376 ret = DefWindowProcA(hwnd, message, wParam, lParam);
3377 defwndproc_counter--;
3379 return ret;
3382 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3384 static long defwndproc_counter = 0;
3385 LRESULT ret;
3386 struct message msg;
3388 trace("parent: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
3390 if (message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
3391 message == WM_SETFOCUS || message == WM_KILLFOCUS ||
3392 message == WM_ENABLE || message == WM_ENTERIDLE ||
3393 message == WM_IME_SETCONTEXT)
3395 msg.message = message;
3396 msg.flags = sent|parent|wparam|lparam;
3397 if (defwndproc_counter) msg.flags |= defwinproc;
3398 msg.wParam = wParam;
3399 msg.lParam = lParam;
3400 add_message(&msg);
3403 defwndproc_counter++;
3404 ret = DefWindowProcA(hwnd, message, wParam, lParam);
3405 defwndproc_counter--;
3407 return ret;
3410 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3412 static long defwndproc_counter = 0;
3413 LRESULT ret;
3414 struct message msg;
3416 trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
3418 DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
3419 ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
3420 if (after_end_dialog)
3421 ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
3422 else
3423 ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
3425 msg.message = message;
3426 msg.flags = sent|wparam|lparam;
3427 if (defwndproc_counter) msg.flags |= defwinproc;
3428 msg.wParam = wParam;
3429 msg.lParam = lParam;
3430 add_message(&msg);
3432 defwndproc_counter++;
3433 ret = DefDlgProcA(hwnd, message, wParam, lParam);
3434 defwndproc_counter--;
3436 return ret;
3439 static BOOL RegisterWindowClasses(void)
3441 WNDCLASSA cls;
3443 cls.style = 0;
3444 cls.lpfnWndProc = MsgCheckProcA;
3445 cls.cbClsExtra = 0;
3446 cls.cbWndExtra = 0;
3447 cls.hInstance = GetModuleHandleA(0);
3448 cls.hIcon = 0;
3449 cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
3450 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
3451 cls.lpszMenuName = NULL;
3452 cls.lpszClassName = "TestWindowClass";
3453 if(!RegisterClassA(&cls)) return FALSE;
3455 cls.lpfnWndProc = PopupMsgCheckProcA;
3456 cls.lpszClassName = "TestPopupClass";
3457 if(!RegisterClassA(&cls)) return FALSE;
3459 cls.lpfnWndProc = ParentMsgCheckProcA;
3460 cls.lpszClassName = "TestParentClass";
3461 if(!RegisterClassA(&cls)) return FALSE;
3463 cls.lpfnWndProc = DefWindowProcA;
3464 cls.lpszClassName = "SimpleWindowClass";
3465 if(!RegisterClassA(&cls)) return FALSE;
3467 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
3468 cls.lpfnWndProc = TestDlgProcA;
3469 cls.lpszClassName = "TestDialogClass";
3470 if(!RegisterClassA(&cls)) return FALSE;
3472 return TRUE;
3475 static HHOOK hCBT_hook;
3477 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
3479 char buf[256];
3481 trace("CBT: %d, %08x, %08lx\n", nCode, wParam, lParam);
3483 if (nCode == HCBT_SYSCOMMAND)
3485 struct message msg;
3487 msg.message = nCode;
3488 msg.flags = hook;
3489 msg.wParam = wParam;
3490 msg.lParam = lParam;
3491 add_message(&msg);
3493 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
3496 /* Log also SetFocus(0) calls */
3497 if (!wParam) wParam = lParam;
3499 if (GetClassNameA((HWND)wParam, buf, sizeof(buf)))
3501 if (!strcmp(buf, "TestWindowClass") ||
3502 !strcmp(buf, "TestParentClass") ||
3503 !strcmp(buf, "TestPopupClass") ||
3504 !strcmp(buf, "SimpleWindowClass") ||
3505 !strcmp(buf, "TestDialogClass") ||
3506 !strcmp(buf, "MDI_frame_class") ||
3507 !strcmp(buf, "MDI_client_class") ||
3508 !strcmp(buf, "MDI_child_class") ||
3509 !strcmp(buf, "my_button_class") ||
3510 !strcmp(buf, "#32770"))
3512 struct message msg;
3514 msg.message = nCode;
3515 msg.flags = hook;
3516 msg.wParam = wParam;
3517 msg.lParam = lParam;
3518 add_message(&msg);
3521 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
3524 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
3525 static const WCHAR wszAnsi[] = {'U',0};
3527 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
3529 switch (uMsg)
3531 case CB_FINDSTRINGEXACT:
3532 trace("String: %p\n", (LPCWSTR)lParam);
3533 if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
3534 return 1;
3535 if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
3536 return 0;
3537 return -1;
3539 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
3542 static void test_message_conversion(void)
3544 static const WCHAR wszMsgConversionClass[] =
3545 {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
3546 WNDCLASSW cls;
3547 LRESULT lRes;
3548 HWND hwnd;
3549 WNDPROC wndproc;
3551 cls.style = 0;
3552 cls.lpfnWndProc = MsgConversionProcW;
3553 cls.cbClsExtra = 0;
3554 cls.cbWndExtra = 0;
3555 cls.hInstance = GetModuleHandleW(NULL);
3556 cls.hIcon = NULL;
3557 cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
3558 cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
3559 cls.lpszMenuName = NULL;
3560 cls.lpszClassName = wszMsgConversionClass;
3561 /* this call will fail on Win9x, but that doesn't matter as this test is
3562 * meaningless on those platforms */
3563 if(!RegisterClassW(&cls)) return;
3565 hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
3566 100, 100, 200, 200, 0, 0, 0, NULL);
3567 ok(hwnd != NULL, "Window creation failed\n");
3569 /* {W, A} -> A */
3571 wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
3572 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3573 ok(lRes == 0, "String should have been converted\n");
3574 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3575 ok(lRes == 1, "String shouldn't have been converted\n");
3577 /* {W, A} -> W */
3579 wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
3580 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3581 ok(lRes == 1, "String shouldn't have been converted\n");
3582 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3583 ok(lRes == 1, "String shouldn't have been converted\n");
3585 /* Synchronous messages */
3587 lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3588 ok(lRes == 0, "String should have been converted\n");
3589 lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3590 ok(lRes == 1, "String shouldn't have been converted\n");
3592 /* Asynchronous messages */
3594 SetLastError(0);
3595 lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3596 ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3597 "PostMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3598 SetLastError(0);
3599 lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3600 ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3601 "PostMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3602 SetLastError(0);
3603 lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3604 ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3605 "PosThreadtMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3606 SetLastError(0);
3607 lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3608 ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3609 "PosThreadtMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3610 SetLastError(0);
3611 lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3612 ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3613 "SendNotifyMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3614 SetLastError(0);
3615 lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3616 ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3617 "SendNotifyMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3618 SetLastError(0);
3619 lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
3620 ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3621 "SendMessageCallback on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3622 SetLastError(0);
3623 lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
3624 ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3625 "SendMessageCallback on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3628 START_TEST(msg)
3630 if (!RegisterWindowClasses()) assert(0);
3632 hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
3633 assert(hCBT_hook);
3635 test_messages();
3636 test_mdi_messages();
3637 test_button_messages();
3638 test_paint_messages();
3639 test_interthread_messages();
3640 test_message_conversion();
3641 test_accelerators();
3643 UnhookWindowsHookEx(hCBT_hook);