VK_0-9 and VK_A-Z are not defined in the Windows headers, removed them
[wine] / dlls / user / tests / msg.c
1 /*
2  * Unit tests for window message handling
3  *
4  * Copyright 1999 Ove Kaaven
5  * Copyright 2003 Dimitrie O. Paun
6  * Copyright 2004 Dmitry Timoshkov
7  *
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.
12  *
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.
17  *
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
21  */
22
23 #include <assert.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26
27 #define _WIN32_WINNT 0x0500 /* For WM_CHANGEUISTATE */
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33
34 #include "wine/test.h"
35
36 #define MDI_FIRST_CHILD_ID 2004
37
38 /* undocumented SWP flags - from SDK 3.1 */
39 #define SWP_NOCLIENTSIZE        0x0800
40 #define SWP_NOCLIENTMOVE        0x1000
41
42 /*
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
50 */
51
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;
63
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 */
69 };
70
71 /* Empty message sequence */
72 static const struct message WmEmptySeq[] =
73 {
74     { 0 }
75 };
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 }
84 };
85 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
86  * for a not visible overlapped window.
87  */
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 }
113 };
114 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
115  * for a visible overlapped window.
116  */
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 }
121 };
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?
152        */
153     { WM_SIZE, sent },
154     { WM_MOVE, sent },
155 #endif
156     { 0 }
157 };
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 }
172 };
173 /* ShowWindow(SW_HIDE) for an invisible overlapped window */
174 static const struct message WmHideInvisibleOverlappedSeq[] = {
175     { 0 }
176 };
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 }
191 };
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 }
201 };
202 /* CreateWindow (for a popup window, not initially visible,
203  * which sets WS_VISIBLE in WM_CREATE handler)
204  */
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 }
215 };
216 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
217  * for a popup window with WS_VISIBLE style set
218  */
219 static const struct message WmShowVisiblePopupSeq_2[] = {
220     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
221     { 0 }
222 };
223 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
224  * for a popup window with WS_VISIBLE style set
225  */
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 }
240 };
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 }
252 };
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 }
269 };
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 }
285 };
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 }
293 };
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 }
301 };
302 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
303  * for a not visible child window
304  */
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 }
310 };
311 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
312  * for a not visible child window
313  */
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 }
318 };
319 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
320  * for a visible child window with a caption
321  */
322 static const struct message WmShowChildSeq_4[] = {
323     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
324     { WM_CHILDACTIVATE, sent },
325     { 0 }
326 };
327 /* ShowWindow(SW_SHOW) for child with invisible parent */
328 static const struct message WmShowChildInvisibleParentSeq[] = {
329     { WM_SHOWWINDOW, sent|wparam, 1 },
330     { 0 }
331 };
332 /* ShowWindow(SW_HIDE) for child with invisible parent */
333 static const struct message WmHideChildInvisibleParentSeq[] = {
334     { WM_SHOWWINDOW, sent|wparam, 0 },
335     { 0 }
336 };
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 }
342 };
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 }
348 };
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 }
367 };
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 }
374 };
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 }
381 };
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 }
393 };
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 }
412 };
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 }
422 };
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 }
442 };
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 }
456 };
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 }
508 };
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 }
533 };
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 }
601 };
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 }
630 };
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 }
644 };
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 }
651 };
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 }
667 };
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 }
678 };
679 /* DrawMenuBar for a visible window */
680 static const struct message WmDrawMenuBarSeq[] =
681 {
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 }
689 };
690
691 static const struct message WmSetRedrawFalseSeq[] =
692 {
693     { WM_SETREDRAW, sent|wparam, 0 },
694     { 0 }
695 };
696
697 static const struct message WmSetRedrawTrueSeq[] =
698 {
699     { WM_SETREDRAW, sent|wparam, 1 },
700     { 0 }
701 };
702
703 static const struct message WmEnableWindowSeq[] =
704 {
705     { WM_CANCELMODE, sent },
706     { WM_ENABLE, sent },
707     { 0 }
708 };
709
710 static const struct message WmGetScrollRangeSeq[] =
711 {
712     { SBM_GETRANGE, sent },
713     { 0 }
714 };
715 static const struct message WmGetScrollInfoSeq[] =
716 {
717     { SBM_GETSCROLLINFO, sent },
718     { 0 }
719 };
720 static const struct message WmSetScrollRangeSeq[] =
721 {
722     /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
723        sends SBM_SETSCROLLINFO.
724      */
725     { SBM_SETSCROLLINFO, sent },
726     { 0 }
727 };
728 /* SetScrollRange for a window without a non-client area */
729 static const struct message WmSetScrollRangeHVSeq[] =
730 {
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 }
737 };
738 /* SetScrollRange for a window with a non-client area */
739 static const struct message WmSetScrollRangeHV_NC_Seq[] =
740 {
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 }
767 };
768
769 static int after_end_dialog;
770 static int sequence_cnt, sequence_size;
771 static struct message* sequence;
772
773 static void add_message(const struct message *msg)
774 {
775     if (!sequence) 
776     {
777         sequence_size = 10;
778         sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof (struct message) );
779     }
780     if (sequence_cnt == sequence_size) 
781     {
782         sequence_size *= 2;
783         sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof (struct message) );
784     }
785     assert(sequence);
786
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;
791
792     sequence_cnt++;
793 }
794
795 static void flush_sequence()
796 {
797     HeapFree(GetProcessHeap(), 0, sequence);
798     sequence = 0;
799     sequence_cnt = sequence_size = 0;
800 }
801
802 static void ok_sequence(const struct message *expected, const char *context, int todo)
803 {
804     static const struct message end_of_sequence = { 0, 0, 0, 0 };
805     const struct message *actual;
806     
807     add_message(&end_of_sequence);
808
809     actual = sequence;
810
811     while (expected->message && actual->message)
812     {
813         trace("expected %04x - actual %04x\n", expected->message, actual->message);
814
815         if (expected->message == actual->message)
816         {
817             if (expected->flags & wparam)
818             {
819                 if (expected->wParam != actual->wParam && todo)
820                 {
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);
825                     }
826                 }
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);
831             }
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++;
853         }
854         else if (expected->flags & optional)
855             expected++;
856         else if (todo)
857         {
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);
861             }
862             flush_sequence();
863             return;
864         }
865         else
866         {
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++;
871         }
872     }
873
874     /* skip all optional trailing messages */
875     while (expected->message && (expected->flags & optional))
876         expected++;
877
878     if (todo)
879     {
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);
884         }
885     }
886     else
887     {
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);
891     }
892
893     flush_sequence();
894 }
895
896 /******************************** MDI test **********************************/
897
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 }
922 };
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 }
934 };
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 }
948 };
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 }
959 };
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
972      */
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 },
981
982     /* Win9x: message sequence terminates here. */
983
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 }
995 };
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
1003      */
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 },
1009
1010     /* { WM_DESTROY, sent }
1011      * Win9x: message sequence terminates here.
1012      */
1013
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 */
1019
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 */
1025
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 */
1031
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 */
1037
1038     { WM_DESTROY, sent },
1039
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 */
1045
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 */
1051
1052     { WM_NCDESTROY, sent },
1053     { 0 }
1054 };
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
1067      */
1068     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1069     { 0 }
1070 };
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
1078      */
1079     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1080     { WM_DESTROY, sent },
1081     { WM_NCDESTROY, sent },
1082     { 0 }
1083 };
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
1106      */
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 },
1115
1116     /* Win9x: message sequence terminates here. */
1117
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 }
1133 };
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
1170      */
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 },
1178
1179     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
1180     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
1181
1182     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1183
1184     /* Win9x: message sequence terminates here. */
1185
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 },
1197
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 }
1204 };
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
1228      */
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 },
1237
1238     /* Win9x: message sequence terminates here. */
1239
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 },
1249
1250     { WM_MDIACTIVATE, sent|defwinproc },
1251
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 },
1256
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 },
1263
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 },
1269
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 },
1275
1276     { 0 }
1277 };
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 */
1284
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 */
1291
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 },
1300
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 },
1313
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 },
1329
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 },
1335
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
1341      */
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 },
1347
1348     { WM_DESTROY, sent|defwinproc },
1349     { WM_NCDESTROY, sent|defwinproc },
1350     { 0 }
1351 };
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 },
1359
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 },
1370
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 },
1375
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 },
1382
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 },
1388
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 },
1394
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 },
1399
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 },
1406
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 },
1412
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 },
1418
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 },
1423
1424     { WM_NCACTIVATE, sent|wparam, 0 },
1425     { WM_MDIACTIVATE, sent },
1426
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 },
1433
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 },
1438
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 },
1445
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 },
1451
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 */
1457
1458     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
1459
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
1465      */
1466     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1467
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 },
1472
1473     { WM_DESTROY, sent },
1474     { WM_NCDESTROY, sent },
1475     { 0 }
1476 };
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 },
1484
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 }
1503 };
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 }
1518 };
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 }
1532 };
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 }
1546 };
1547
1548 static HWND mdi_client;
1549 static WNDPROC old_mdi_client_proc;
1550
1551 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1552 {
1553     struct message msg;
1554
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)
1561     {
1562         trace("mdi client: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1563
1564         switch (message)
1565         {
1566             case WM_WINDOWPOSCHANGING:
1567             case WM_WINDOWPOSCHANGED:
1568             {
1569                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
1570
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);
1575
1576                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
1577                  * in the high word for internal purposes
1578                  */
1579                 wParam = winpos->flags & 0xffff;
1580                 break;
1581             }
1582         }
1583
1584         msg.message = message;
1585         msg.flags = sent|wparam|lparam;
1586         msg.wParam = wParam;
1587         msg.lParam = lParam;
1588         add_message(&msg);
1589     }
1590
1591     return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
1592 }
1593
1594 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1595 {
1596     static long defwndproc_counter = 0;
1597     LRESULT ret;
1598     struct message msg;
1599
1600     /* do not log painting messages */
1601     if (message != WM_PAINT &&
1602         message != WM_ERASEBKGND &&
1603         message != WM_NCPAINT &&
1604         message != WM_GETTEXT)
1605     {
1606         trace("mdi child: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1607
1608         switch (message)
1609         {
1610             case WM_WINDOWPOSCHANGING:
1611             case WM_WINDOWPOSCHANGED:
1612             {
1613                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
1614
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);
1619
1620                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
1621                  * in the high word for internal purposes
1622                  */
1623                 wParam = winpos->flags & 0xffff;
1624                 break;
1625             }
1626
1627             case WM_MDIACTIVATE:
1628             {
1629                 HWND active, client = GetParent(hwnd);
1630
1631                 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
1632
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;
1638             }
1639         }
1640
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);
1647     }
1648
1649     defwndproc_counter++;
1650     ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
1651     defwndproc_counter--;
1652
1653     return ret;
1654 }
1655
1656 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1657 {
1658     static long defwndproc_counter = 0;
1659     LRESULT ret;
1660     struct message msg;
1661
1662     /* do not log painting messages */
1663     if (message != WM_PAINT &&
1664         message != WM_ERASEBKGND &&
1665         message != WM_NCPAINT &&
1666         message != WM_GETTEXT)
1667     {
1668         trace("mdi frame: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1669
1670         switch (message)
1671         {
1672             case WM_WINDOWPOSCHANGING:
1673             case WM_WINDOWPOSCHANGED:
1674             {
1675                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
1676
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);
1681
1682                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
1683                  * in the high word for internal purposes
1684                  */
1685                 wParam = winpos->flags & 0xffff;
1686                 break;
1687             }
1688         }
1689
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);
1696     }
1697
1698     defwndproc_counter++;
1699     ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
1700     defwndproc_counter--;
1701
1702     return ret;
1703 }
1704
1705 static BOOL mdi_RegisterWindowClasses(void)
1706 {
1707     WNDCLASSA cls;
1708
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;
1720
1721     cls.lpfnWndProc = mdi_child_wnd_proc;
1722     cls.lpszClassName = "MDI_child_class";
1723     if (!RegisterClassA(&cls)) return FALSE;
1724
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);
1731
1732     return TRUE;
1733 }
1734
1735 static void test_mdi_messages(void)
1736 {
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();
1742
1743     assert(mdi_RegisterWindowClasses());
1744
1745     flush_sequence();
1746
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);
1756
1757     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1758     ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
1759
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);
1770
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());
1773
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);
1777
1778     SetFocus(0);
1779     flush_sequence();
1780
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);
1788
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");
1791
1792     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1793     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
1794
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();
1799
1800     DestroyWindow(mdi_child);
1801     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
1802
1803     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1804     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1805
1806     /* Win2k: MDI client still returns a just destroyed child as active
1807      * Win9x: MDI client returns 0
1808      */
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);
1814
1815     flush_sequence();
1816
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);
1824
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");
1827
1828     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1829     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1830
1831     /* Win2k: MDI client still returns a just destroyed child as active
1832      * Win9x: MDI client returns mdi_child2
1833      */
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();
1840
1841     ShowWindow(mdi_child2, SW_MAXIMIZE);
1842     ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", TRUE);
1843
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");
1846
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();
1851
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());
1856
1857     SetFocus(0);
1858     flush_sequence();
1859
1860     ShowWindow(mdi_child2, SW_HIDE);
1861     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
1862
1863     ShowWindow(mdi_child2, SW_RESTORE);
1864     ok_sequence(WmRestoreMDIchildInisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", TRUE);
1865     flush_sequence();
1866
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");
1869
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();
1874
1875     SetFocus(0);
1876     flush_sequence();
1877
1878     ShowWindow(mdi_child2, SW_HIDE);
1879     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
1880
1881     ShowWindow(mdi_child2, SW_SHOW);
1882     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", TRUE);
1883
1884     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1885     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1886
1887     ShowWindow(mdi_child2, SW_MAXIMIZE);
1888     ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", TRUE);
1889
1890     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1891     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1892
1893     ShowWindow(mdi_child2, SW_RESTORE);
1894     ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):MDI child", TRUE);
1895
1896     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1897     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1898
1899     SetFocus(0);
1900     flush_sequence();
1901
1902     ShowWindow(mdi_child2, SW_HIDE);
1903     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
1904
1905     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1906     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1907
1908     DestroyWindow(mdi_child2);
1909     ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", TRUE);
1910
1911     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1912     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1913
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");
1923
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());
1928
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();
1933
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");
1943
1944     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1945     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
1946
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();
1951
1952     trace("destroying maximized visible MDI child window 2\n");
1953     DestroyWindow(mdi_child2);
1954     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
1955
1956     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
1957
1958     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1959     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1960
1961     /* Win2k: MDI client still returns a just destroyed child as active
1962      * Win9x: MDI client returns 0
1963      */
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();
1969
1970     ShowWindow(mdi_child, SW_MAXIMIZE);
1971     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
1972     flush_sequence();
1973
1974     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1975     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
1976
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");
1986
1987     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1988     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
1989
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();
1994
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");
1998
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());
2002
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();
2007
2008     DestroyWindow(mdi_child);
2009     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
2010
2011     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2012     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2013
2014     /* Win2k: MDI client still returns a just destroyed child as active
2015      * Win9x: MDI client returns 0
2016      */
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 */
2023
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);
2036
2037     ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
2038
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);
2041
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());
2045
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();
2050
2051     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
2052     ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
2053
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);
2057
2058     SetFocus(0);
2059     flush_sequence();
2060
2061     DestroyWindow(mdi_client);
2062     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
2063
2064     DestroyWindow(mdi_frame);
2065     ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
2066 }
2067 /************************* End of MDI test **********************************/
2068
2069 static void test_WM_SETREDRAW(HWND hwnd)
2070 {
2071     DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
2072
2073     flush_sequence();
2074
2075     SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
2076     ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
2077
2078     ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
2079     ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
2080
2081     flush_sequence();
2082     SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
2083     ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
2084
2085     ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
2086     ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
2087
2088     /* restore original WS_VISIBLE state */
2089     SetWindowLongA(hwnd, GWL_STYLE, style);
2090
2091     flush_sequence();
2092 }
2093
2094 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2095 {
2096     struct message msg;
2097
2098     trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2099
2100     msg.message = message;
2101     msg.flags = sent|wparam|lparam;
2102     msg.wParam = wParam;
2103     msg.lParam = lParam;
2104     add_message(&msg);
2105
2106     if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
2107     if (message == WM_TIMER) EndDialog( hwnd, 0 );
2108     return 0;
2109 }
2110
2111 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
2112 {
2113     DWORD style, exstyle;
2114     INT xmin, xmax;
2115
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;
2120
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);
2123
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);
2129
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);
2133
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);
2137
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);
2145 }
2146
2147 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
2148 {
2149     DWORD style, exstyle;
2150     SCROLLINFO si;
2151
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;
2156
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);
2159
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);
2169
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);
2173
2174     /* a subsequent call should do nothing */
2175     SetScrollInfo(hwnd, ctl, &si, TRUE);
2176     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
2177
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);
2182
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);
2187
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);
2195 }
2196
2197 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
2198 static void test_scroll_messages(HWND hwnd)
2199 {
2200     SCROLLINFO si;
2201     INT min, max;
2202
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();
2210
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();
2215
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();
2223
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();
2232
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();
2239
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();
2246
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();
2255
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);
2260
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);
2265
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);
2270
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);
2275 }
2276
2277 /* test if we receive the right sequence of messages */
2278 static void test_messages(void)
2279 {
2280     HWND hwnd, hparent, hchild;
2281     HWND hchild2, hbutton;
2282     HMENU hmenu;
2283
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);
2288
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);
2292
2293     /* test WM_SETREDRAW on a not visible top level window */
2294     test_WM_SETREDRAW(hwnd);
2295
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");
2299
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);
2304     
2305     ShowWindow(hwnd, SW_SHOW);
2306     ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
2307
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");
2313
2314     /* test WM_SETREDRAW on a visible top level window */
2315     ShowWindow(hwnd, SW_SHOW);
2316     test_WM_SETREDRAW(hwnd);
2317
2318     trace("testing scroll APIs on a visible top level window %p\n", hwnd);
2319     test_scroll_messages(hwnd);
2320
2321     DestroyWindow(hwnd);
2322     ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
2323
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();
2328
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();
2335
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);
2342
2343     trace("testing scroll APIs on a visible child window %p\n", hchild);
2344     test_scroll_messages(hchild);
2345
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);
2348
2349     DestroyWindow(hchild);
2350     flush_sequence();
2351
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);
2356     
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();
2361
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");
2365
2366     /* test WM_SETREDRAW on a not visible child window */
2367     test_WM_SETREDRAW(hchild);
2368
2369     ShowWindow(hchild, SW_SHOW);
2370     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
2371
2372     ShowWindow(hchild, SW_HIDE);
2373     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
2374
2375     ShowWindow(hchild, SW_SHOW);
2376     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
2377
2378     /* test WM_SETREDRAW on a visible child window */
2379     test_WM_SETREDRAW(hchild);
2380
2381     MoveWindow(hchild, 10, 10, 20, 20, TRUE);
2382     ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
2383
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);
2388
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);
2393
2394     /* DestroyWindow sequence below expects that a child has focus */
2395     SetFocus(hchild);
2396     flush_sequence();
2397
2398     DestroyWindow(hchild);
2399     ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
2400     DestroyWindow(hchild2);
2401     DestroyWindow(hbutton);
2402
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);
2409
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);
2428
2429     /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
2430      * changes nothing in message sequences.
2431      */
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);
2446
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);
2452
2453     trace("testing scroll APIs on a visible dialog %p\n", hwnd);
2454     test_scroll_messages(hwnd);
2455
2456     flush_sequence();
2457     after_end_dialog = 1;
2458     EndDialog( hwnd, 0 );
2459     ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
2460
2461     DestroyWindow(hwnd);
2462     after_end_dialog = 0;
2463
2464     flush_sequence();
2465     DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
2466     ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
2467
2468     /* test showing child with hidden parent */
2469     ShowWindow( hparent, SW_HIDE );
2470     flush_sequence();
2471
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);
2476
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");
2481
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");
2486
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");
2491
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");
2496
2497     DestroyWindow(hchild);
2498     DestroyWindow(hparent);
2499     flush_sequence();
2500
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);
2504
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);
2521
2522     ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
2523     ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", TRUE);
2524
2525     DestroyWindow(hwnd);
2526     flush_sequence();
2527
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");
2535
2536     SetFocus(hchild);
2537     flush_sequence();
2538
2539     EnableWindow(hparent, FALSE);
2540     ok_sequence(WmEnableWindowSeq, "EnableWindow", FALSE);
2541
2542     DestroyWindow(hchild);
2543     DestroyWindow(hparent);
2544     flush_sequence();
2545 }
2546
2547 /****************** button message test *************************/
2548 static const struct message WmSetFocusButtonSeq[] =
2549 {
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 }
2555 };
2556 static const struct message WmKillFocusButtonSeq[] =
2557 {
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 }
2563 };
2564 static const struct message WmSetFocusStaticSeq[] =
2565 {
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 }
2571 };
2572 static const struct message WmKillFocusStaticSeq[] =
2573 {
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 }
2579 };
2580 static const struct message WmLButtonDownSeq[] =
2581 {
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 }
2590 };
2591 static const struct message WmLButtonUpSeq[] =
2592 {
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 }
2598 };
2599
2600 static WNDPROC old_button_proc;
2601
2602 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2603 {
2604     static long defwndproc_counter = 0;
2605     LRESULT ret;
2606     struct message msg;
2607
2608     trace("button: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2609
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);
2616
2617     if (message == BM_SETSTATE)
2618         ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
2619
2620     defwndproc_counter++;
2621     ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
2622     defwndproc_counter--;
2623
2624     return ret;
2625 }
2626
2627 static void subclass_button(void)
2628 {
2629     WNDCLASSA cls;
2630
2631     if (!GetClassInfoA(0, "button", &cls)) assert(0);
2632
2633     old_button_proc = cls.lpfnWndProc;
2634
2635     cls.hInstance = GetModuleHandle(0);
2636     cls.lpfnWndProc = button_hook_proc;
2637     cls.lpszClassName = "my_button_class";
2638     if (!RegisterClassA(&cls)) assert(0);
2639 }
2640
2641 static void test_button_messages(void)
2642 {
2643     static const struct
2644     {
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 }
2660     };
2661     unsigned int i;
2662     HWND hwnd;
2663
2664     subclass_button();
2665
2666     for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
2667     {
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");
2671
2672         ShowWindow(hwnd, SW_SHOW);
2673         UpdateWindow(hwnd);
2674         SetFocus(0);
2675         flush_sequence();
2676
2677         trace("button style %08lx\n", button[i].style);
2678         SetFocus(hwnd);
2679         ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
2680
2681         SetFocus(0);
2682         ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
2683
2684         DestroyWindow(hwnd);
2685     }
2686
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");
2690
2691     SetFocus(0);
2692     flush_sequence();
2693
2694     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
2695     ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
2696
2697     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
2698     ok_sequence(WmLButtonUpSeq, "WM_LBUTTONDOWN on a button", FALSE);
2699     DestroyWindow(hwnd);
2700 }
2701
2702 /************* painting message test ********************/
2703
2704 static void dump_region(HRGN hrgn)
2705 {
2706     DWORD i, size;
2707     RGNDATA *data = NULL;
2708     RECT *rect;
2709
2710     if (!hrgn)
2711     {
2712         printf( "null region\n" );
2713         return;
2714     }
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 );
2723 }
2724
2725 static void check_update_rgn( HWND hwnd, HRGN hrgn )
2726 {
2727     INT ret;
2728     RECT r1, r2;
2729     HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
2730     HRGN update = CreateRectRgn( 0, 0, 0, 0 );
2731
2732     ret = GetUpdateRgn( hwnd, update, FALSE );
2733     ok( ret != ERROR, "GetUpdateRgn failed\n" );
2734     if (ret == NULLREGION)
2735     {
2736         ok( !hrgn, "Update region shouldn't be empty\n" );
2737     }
2738     else
2739     {
2740         if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
2741         {
2742             ok( 0, "Regions are different\n" );
2743             if (winetest_debug > 0)
2744             {
2745                 printf( "Update region: " );
2746                 dump_region( update );
2747                 printf( "Wanted region: " );
2748                 dump_region( hrgn );
2749             }
2750         }
2751     }
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 );
2757
2758     DeleteObject( tmp );
2759     DeleteObject( update );
2760 }
2761
2762 static const struct message WmInvalidateRgn[] = {
2763     { WM_NCPAINT, sent },
2764     { WM_GETTEXT, sent|defwinproc|optional },
2765     { 0 }
2766 };
2767
2768 static const struct message WmInvalidateFull[] = {
2769     { WM_NCPAINT, sent|wparam, 1 },
2770     { WM_GETTEXT, sent|defwinproc|optional },
2771     { 0 }
2772 };
2773
2774 static const struct message WmInvalidateErase[] = {
2775     { WM_NCPAINT, sent|wparam, 1 },
2776     { WM_GETTEXT, sent|defwinproc|optional },
2777     { WM_ERASEBKGND, sent },
2778     { 0 }
2779 };
2780
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 }
2786 };
2787
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 }
2794 };
2795
2796 static const struct message WmErase[] = {
2797     { WM_ERASEBKGND, sent },
2798     { 0 }
2799 };
2800
2801 static const struct message WmPaint[] = {
2802     { WM_PAINT, sent },
2803     { 0 }
2804 };
2805
2806 static void test_paint_messages(void)
2807 {
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");
2815
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 );
2831
2832     flush_sequence();
2833     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
2834     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
2835
2836     SetRectRgn( hrgn, 0, 0, 20, 20 );  /* GetUpdateRgn clips to client area */
2837     check_update_rgn( hwnd, hrgn );
2838
2839     flush_sequence();
2840     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
2841     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
2842
2843     flush_sequence();
2844     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
2845     ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
2846
2847     GetClientRect( hwnd, &rect );
2848     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
2849     check_update_rgn( hwnd, hrgn );
2850
2851     flush_sequence();
2852     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
2853     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
2854
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 );
2859
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 );
2864
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 );
2875
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 );
2884
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 );
2891
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 );
2898
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 );
2907
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 );
2915
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 ))
2920     {
2921         if (msg.hwnd == hwnd && msg.message == WM_PAINT)
2922         {
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 );
2931         }
2932         else DispatchMessage( &msg );
2933     }
2934     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
2935
2936     DeleteObject( hrgn );
2937     DeleteObject( hrgn2 );
2938     DestroyWindow( hwnd );
2939 }
2940
2941 struct wnd_event
2942 {
2943     HWND hwnd;
2944     HANDLE event;
2945 };
2946
2947 static DWORD WINAPI thread_proc(void *param)
2948 {
2949     MSG msg;
2950     struct wnd_event *wnd_event = (struct wnd_event *)param;
2951
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");
2955
2956     SetEvent(wnd_event->event);
2957
2958     while (GetMessage(&msg, 0, 0, 0))
2959     {
2960         TranslateMessage(&msg);
2961         DispatchMessage(&msg);
2962     }
2963
2964     return 0;
2965 }
2966
2967 static void test_interthread_messages(void)
2968 {
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;
2976
2977     wnd_event.event = CreateEventW(NULL, 0, 0, NULL);
2978     if (!wnd_event.event)
2979     {
2980         trace("skipping interthread message test under win9x\n");
2981         return;
2982     }
2983
2984     hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
2985     ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError());
2986
2987     ok(WaitForSingleObject(wnd_event.event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2988
2989     CloseHandle(wnd_event.event);
2990
2991     SetLastError(0xdeadbeef);
2992     ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeded\n");
2993     ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error code %ld\n", GetLastError());
2994
2995     proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
2996     ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %ld\n", GetLastError());
2997
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");
3004
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());
3014
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());
3024
3025     ok(PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0), "PostMessageA(WM_QUIT) error %ld\n", GetLastError());
3026
3027     ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
3028     CloseHandle(hThread);
3029 }
3030
3031
3032 static const struct message WmVkN[] = {
3033     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
3034     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
3035     { WM_CHAR, wparam|lparam, 'n', 1 },
3036     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
3037     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
3038     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
3039     { 0 }
3040 };
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, 'N', 1 },
3045     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
3046     { WM_CHAR, wparam|lparam, 'N', 1 },
3047     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
3048     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
3049     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
3050     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
3051     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
3052     { 0 }
3053 };
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, 'N', 1 },
3058     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
3059     { WM_CHAR, wparam|lparam, 0x000e, 1 },
3060     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
3061     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
3062     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
3063     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
3064     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
3065     { 0 }
3066 };
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, 'N', 1 },
3071     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
3072     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
3073     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
3074     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
3075     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
3076     { 0 }
3077 };
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, 'N', 0x20000001 },
3082     { WM_SYSKEYDOWN, sent|wparam|lparam, '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, 'N', 0xe0000001 },
3097     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
3098     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
3099     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
3100     { 0 }
3101 };
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, 'N', 0x20000001 },
3106     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
3107     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
3108     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
3109     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
3110     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
3111     { 0 }
3112 };
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, 'N', 0x20000001 },
3119     { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
3120     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
3121     { WM_KEYUP, sent|wparam|lparam, '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 }
3127 };
3128
3129 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
3130 {
3131     MSG msg;
3132
3133     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
3134     {
3135         struct message log_msg;
3136
3137         trace("accel: %p, %04x, %08x, %08lx\n", msg.hwnd, msg.message, msg.wParam, msg.lParam);
3138
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);
3144
3145         if (!TranslateAccelerator(hwnd, hAccel, &msg))
3146         {
3147             TranslateMessage(&msg);
3148             DispatchMessage(&msg);
3149         }
3150     }
3151 }
3152
3153 static void test_accelerators(void)
3154 {
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);
3160
3161     SetFocus(hwnd);
3162     ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
3163
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);
3168
3169     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(1));
3170     assert(hAccel != 0);
3171
3172     trace("testing VK_N press/release\n");
3173     flush_sequence();
3174     keybd_event('N', 0, 0, 0);
3175     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3176     pump_msg_loop(hwnd, hAccel);
3177     ok_sequence(WmVkN, "VK_N press/release", FALSE);
3178
3179     trace("testing Shift+VK_N press/release\n");
3180     flush_sequence();
3181     keybd_event(VK_SHIFT, 0, 0, 0);
3182     keybd_event('N', 0, 0, 0);
3183     keybd_event('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);
3187
3188     trace("testing Ctrl+VK_N press/release\n");
3189     flush_sequence();
3190     keybd_event(VK_CONTROL, 0, 0, 0);
3191     keybd_event('N', 0, 0, 0);
3192     keybd_event('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);
3196
3197     trace("testing Alt+VK_N press/release\n");
3198     flush_sequence();
3199     keybd_event(VK_MENU, 0, 0, 0);
3200     keybd_event('N', 0, 0, 0);
3201     keybd_event('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);
3205
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('N', 0, 0, 0);
3211     keybd_event('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);
3216
3217     ok(DestroyAcceleratorTable(hAccel), "DestroyAcceleratorTable error %ld\n", GetLastError());
3218
3219     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(2));
3220     assert(hAccel != 0);
3221
3222     trace("testing VK_N press/release\n");
3223     flush_sequence();
3224     keybd_event('N', 0, 0, 0);
3225     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3226     pump_msg_loop(hwnd, hAccel);
3227     ok_sequence(WmVkN, "VK_N press/release", FALSE);
3228
3229     trace("testing Shift+VK_N press/release\n");
3230     flush_sequence();
3231     keybd_event(VK_SHIFT, 0, 0, 0);
3232     keybd_event('N', 0, 0, 0);
3233     keybd_event('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);
3237
3238     trace("testing Ctrl+VK_N press/release 2\n");
3239     flush_sequence();
3240     keybd_event(VK_CONTROL, 0, 0, 0);
3241     keybd_event('N', 0, 0, 0);
3242     keybd_event('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);
3246
3247     trace("testing Alt+VK_N press/release 2\n");
3248     flush_sequence();
3249     keybd_event(VK_MENU, 0, 0, 0);
3250     keybd_event('N', 0, 0, 0);
3251     keybd_event('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);
3255
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('N', 0, 0, 0);
3261     keybd_event('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);
3266
3267     ok(DestroyAcceleratorTable(hAccel), "DestroyAcceleratorTable error %ld\n", GetLastError());
3268
3269     DestroyWindow(hwnd);
3270 }
3271
3272 /************* window procedures ********************/
3273
3274 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3275 {
3276     static long defwndproc_counter = 0;
3277     static long beginpaint_counter = 0;
3278     LRESULT ret;
3279     struct message msg;
3280
3281     trace("%p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
3282
3283     switch (message)
3284     {
3285         case WM_WINDOWPOSCHANGING:
3286         case WM_WINDOWPOSCHANGED:
3287         {
3288             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
3289
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);
3294
3295             /* Log only documented flags, win2k uses 0x1000 and 0x2000
3296              * in the high word for internal purposes
3297              */
3298             wParam = winpos->flags & 0xffff;
3299             break;
3300         }
3301     }
3302
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);
3310
3311     if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
3312     {
3313         HWND parent = GetParent(hwnd);
3314         RECT rc;
3315         MINMAXINFO *minmax = (MINMAXINFO *)lParam;
3316
3317         GetClientRect(parent, &rc);
3318         trace("parent %p client size = (%ld x %ld)\n", parent, rc.right, rc.bottom);
3319
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);
3330
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);
3335     }
3336
3337     if (message == WM_PAINT)
3338     {
3339         PAINTSTRUCT ps;
3340         beginpaint_counter++;
3341         BeginPaint( hwnd, &ps );
3342         beginpaint_counter--;
3343         EndPaint( hwnd, &ps );
3344         return 0;
3345     }
3346
3347     defwndproc_counter++;
3348     ret = DefWindowProcA(hwnd, message, wParam, lParam);
3349     defwndproc_counter--;
3350
3351     return ret;
3352 }
3353
3354 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3355 {
3356     static long defwndproc_counter = 0;
3357     LRESULT ret;
3358     struct message msg;
3359
3360     trace("popup: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
3361
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);
3368
3369     if (message == WM_CREATE)
3370     {
3371         DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
3372         SetWindowLongA(hwnd, GWL_STYLE, style);
3373     }
3374
3375     defwndproc_counter++;
3376     ret = DefWindowProcA(hwnd, message, wParam, lParam);
3377     defwndproc_counter--;
3378
3379     return ret;
3380 }
3381
3382 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3383 {
3384     static long defwndproc_counter = 0;
3385     LRESULT ret;
3386     struct message msg;
3387
3388     trace("parent: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
3389
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)
3394     {
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);
3401     }
3402
3403     defwndproc_counter++;
3404     ret = DefWindowProcA(hwnd, message, wParam, lParam);
3405     defwndproc_counter--;
3406
3407     return ret;
3408 }
3409
3410 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3411 {
3412     static long defwndproc_counter = 0;
3413     LRESULT ret;
3414     struct message msg;
3415
3416     trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
3417
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);
3424
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);
3431
3432     defwndproc_counter++;
3433     ret = DefDlgProcA(hwnd, message, wParam, lParam);
3434     defwndproc_counter--;
3435
3436     return ret;
3437 }
3438
3439 static BOOL RegisterWindowClasses(void)
3440 {
3441     WNDCLASSA cls;
3442
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;
3454
3455     cls.lpfnWndProc = PopupMsgCheckProcA;
3456     cls.lpszClassName = "TestPopupClass";
3457     if(!RegisterClassA(&cls)) return FALSE;
3458
3459     cls.lpfnWndProc = ParentMsgCheckProcA;
3460     cls.lpszClassName = "TestParentClass";
3461     if(!RegisterClassA(&cls)) return FALSE;
3462
3463     cls.lpfnWndProc = DefWindowProcA;
3464     cls.lpszClassName = "SimpleWindowClass";
3465     if(!RegisterClassA(&cls)) return FALSE;
3466
3467     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
3468     cls.lpfnWndProc = TestDlgProcA;
3469     cls.lpszClassName = "TestDialogClass";
3470     if(!RegisterClassA(&cls)) return FALSE;
3471
3472     return TRUE;
3473 }
3474
3475 static HHOOK hCBT_hook;
3476
3477 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
3478
3479     char buf[256];
3480
3481     trace("CBT: %d, %08x, %08lx\n", nCode, wParam, lParam);
3482
3483     if (nCode == HCBT_SYSCOMMAND)
3484     {
3485         struct message msg;
3486
3487         msg.message = nCode;
3488         msg.flags = hook;
3489         msg.wParam = wParam;
3490         msg.lParam = lParam;
3491         add_message(&msg);
3492
3493         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
3494     }
3495
3496     /* Log also SetFocus(0) calls */
3497     if (!wParam) wParam = lParam;
3498
3499     if (GetClassNameA((HWND)wParam, buf, sizeof(buf)))
3500     {
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"))
3511         {
3512             struct message msg;
3513
3514             msg.message = nCode;
3515             msg.flags = hook;
3516             msg.wParam = wParam;
3517             msg.lParam = lParam;
3518             add_message(&msg);
3519         }
3520     }
3521     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
3522 }
3523
3524 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
3525 static const WCHAR wszAnsi[] = {'U',0};
3526
3527 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
3528 {
3529     switch (uMsg)
3530     {
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;
3538     }
3539     return DefWindowProcW(hwnd, uMsg, wParam, lParam);
3540 }
3541
3542 static void test_message_conversion(void)
3543 {
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;
3550
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;
3564
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");
3568
3569     /* {W, A} -> A */
3570
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");
3576
3577     /* {W, A} -> W */
3578
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");
3584
3585     /* Synchronous messages */
3586
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");
3591
3592     /* Asynchronous messages */
3593
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());
3626 }
3627
3628 START_TEST(msg)
3629 {
3630     if (!RegisterWindowClasses()) assert(0);
3631
3632     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
3633     assert(hCBT_hook);
3634
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();
3642
3643     UnhookWindowsHookEx(hCBT_hook);
3644 }