Make button return exactly the same dialog codes as Windows does.
[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         DWORD dlg_code;
2647         const struct message *setfocus;
2648         const struct message *killfocus;
2649     } button[] = {
2650         { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
2651           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
2652         { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
2653           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
2654         { BS_CHECKBOX, DLGC_BUTTON,
2655           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2656         { BS_AUTOCHECKBOX, DLGC_BUTTON,
2657           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2658         { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
2659           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2660         { BS_3STATE, DLGC_BUTTON,
2661           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2662         { BS_AUTO3STATE, DLGC_BUTTON,
2663           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2664         { BS_GROUPBOX, DLGC_STATIC,
2665           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2666         { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
2667           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
2668         { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
2669           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2670         { BS_OWNERDRAW, DLGC_BUTTON,
2671           WmSetFocusButtonSeq, WmKillFocusButtonSeq }
2672     };
2673     unsigned int i;
2674     HWND hwnd;
2675     DWORD dlg_code;
2676
2677     subclass_button();
2678
2679     for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
2680     {
2681         hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP,
2682                                0, 0, 50, 14, 0, 0, 0, NULL);
2683         ok(hwnd != 0, "Failed to create button window\n");
2684
2685         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
2686         ok(dlg_code == button[i].dlg_code, "%d: wrong dlg_code %08lx\n", i, dlg_code);
2687
2688         ShowWindow(hwnd, SW_SHOW);
2689         UpdateWindow(hwnd);
2690         SetFocus(0);
2691         flush_sequence();
2692
2693         trace("button style %08lx\n", button[i].style);
2694         SetFocus(hwnd);
2695         ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
2696
2697         SetFocus(0);
2698         ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
2699
2700         DestroyWindow(hwnd);
2701     }
2702
2703     hwnd = CreateWindowExA(0, "my_button_class", "test", BS_PUSHBUTTON | WS_POPUP | WS_VISIBLE,
2704                            0, 0, 50, 14, 0, 0, 0, NULL);
2705     ok(hwnd != 0, "Failed to create button window\n");
2706
2707     SetFocus(0);
2708     flush_sequence();
2709
2710     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
2711     ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
2712
2713     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
2714     ok_sequence(WmLButtonUpSeq, "WM_LBUTTONDOWN on a button", FALSE);
2715     DestroyWindow(hwnd);
2716 }
2717
2718 /************* painting message test ********************/
2719
2720 static void dump_region(HRGN hrgn)
2721 {
2722     DWORD i, size;
2723     RGNDATA *data = NULL;
2724     RECT *rect;
2725
2726     if (!hrgn)
2727     {
2728         printf( "null region\n" );
2729         return;
2730     }
2731     if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
2732     if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
2733     GetRegionData( hrgn, size, data );
2734     printf("%ld rects:", data->rdh.nCount );
2735     for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
2736         printf( " (%ld,%ld)-(%ld,%ld)", rect->left, rect->top, rect->right, rect->bottom );
2737     printf("\n");
2738     HeapFree( GetProcessHeap(), 0, data );
2739 }
2740
2741 static void check_update_rgn( HWND hwnd, HRGN hrgn )
2742 {
2743     INT ret;
2744     RECT r1, r2;
2745     HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
2746     HRGN update = CreateRectRgn( 0, 0, 0, 0 );
2747
2748     ret = GetUpdateRgn( hwnd, update, FALSE );
2749     ok( ret != ERROR, "GetUpdateRgn failed\n" );
2750     if (ret == NULLREGION)
2751     {
2752         ok( !hrgn, "Update region shouldn't be empty\n" );
2753     }
2754     else
2755     {
2756         if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
2757         {
2758             ok( 0, "Regions are different\n" );
2759             if (winetest_debug > 0)
2760             {
2761                 printf( "Update region: " );
2762                 dump_region( update );
2763                 printf( "Wanted region: " );
2764                 dump_region( hrgn );
2765             }
2766         }
2767     }
2768     GetRgnBox( update, &r1 );
2769     GetUpdateRect( hwnd, &r2, FALSE );
2770     ok( r1.left == r2.left && r1.top == r2.top && r1.right == r2.right && r1.bottom == r2.bottom,
2771         "Rectangles are different: %ld,%ld-%ld,%ld / %ld,%ld-%ld,%ld\n",
2772         r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom );
2773
2774     DeleteObject( tmp );
2775     DeleteObject( update );
2776 }
2777
2778 static const struct message WmInvalidateRgn[] = {
2779     { WM_NCPAINT, sent },
2780     { WM_GETTEXT, sent|defwinproc|optional },
2781     { 0 }
2782 };
2783
2784 static const struct message WmInvalidateFull[] = {
2785     { WM_NCPAINT, sent|wparam, 1 },
2786     { WM_GETTEXT, sent|defwinproc|optional },
2787     { 0 }
2788 };
2789
2790 static const struct message WmInvalidateErase[] = {
2791     { WM_NCPAINT, sent|wparam, 1 },
2792     { WM_GETTEXT, sent|defwinproc|optional },
2793     { WM_ERASEBKGND, sent },
2794     { 0 }
2795 };
2796
2797 static const struct message WmInvalidatePaint[] = {
2798     { WM_PAINT, sent },
2799     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
2800     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
2801     { 0 }
2802 };
2803
2804 static const struct message WmInvalidateErasePaint[] = {
2805     { WM_PAINT, sent },
2806     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
2807     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
2808     { WM_ERASEBKGND, sent|beginpaint },
2809     { 0 }
2810 };
2811
2812 static const struct message WmErase[] = {
2813     { WM_ERASEBKGND, sent },
2814     { 0 }
2815 };
2816
2817 static const struct message WmPaint[] = {
2818     { WM_PAINT, sent },
2819     { 0 }
2820 };
2821
2822 static void test_paint_messages(void)
2823 {
2824     RECT rect;
2825     MSG msg;
2826     HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
2827     HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
2828     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
2829                                 100, 100, 200, 200, 0, 0, 0, NULL);
2830     ok (hwnd != 0, "Failed to create overlapped window\n");
2831
2832     ShowWindow( hwnd, SW_SHOW );
2833     UpdateWindow( hwnd );
2834     check_update_rgn( hwnd, 0 );
2835     SetRectRgn( hrgn, 10, 10, 20, 20 );
2836     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
2837     check_update_rgn( hwnd, hrgn );
2838     SetRectRgn( hrgn2, 20, 20, 30, 30 );
2839     RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
2840     CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
2841     check_update_rgn( hwnd, hrgn );
2842     /* validate everything */
2843     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
2844     check_update_rgn( hwnd, 0 );
2845     /* now with frame */
2846     SetRectRgn( hrgn, -5, -5, 20, 20 );
2847
2848     flush_sequence();
2849     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
2850     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
2851
2852     SetRectRgn( hrgn, 0, 0, 20, 20 );  /* GetUpdateRgn clips to client area */
2853     check_update_rgn( hwnd, hrgn );
2854
2855     flush_sequence();
2856     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
2857     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
2858
2859     flush_sequence();
2860     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
2861     ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
2862
2863     GetClientRect( hwnd, &rect );
2864     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
2865     check_update_rgn( hwnd, hrgn );
2866
2867     flush_sequence();
2868     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
2869     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
2870
2871     flush_sequence();
2872     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
2873     ok_sequence( WmInvalidatePaint, "InvalidatePaint", TRUE );
2874     check_update_rgn( hwnd, 0 );
2875
2876     flush_sequence();
2877     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
2878     ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
2879     check_update_rgn( hwnd, 0 );
2880
2881     flush_sequence();
2882     SetRectRgn( hrgn, 0, 0, 100, 100 );
2883     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
2884     SetRectRgn( hrgn, 0, 0, 50, 100 );
2885     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
2886     SetRectRgn( hrgn, 50, 0, 100, 100 );
2887     check_update_rgn( hwnd, hrgn );
2888     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
2889     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );  /* must not generate messages, everything is valid */
2890     check_update_rgn( hwnd, 0 );
2891
2892     flush_sequence();
2893     SetRectRgn( hrgn, 0, 0, 100, 100 );
2894     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
2895     SetRectRgn( hrgn, 0, 0, 100, 50 );
2896     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
2897     ok_sequence( WmErase, "Erase", FALSE );
2898     SetRectRgn( hrgn, 0, 50, 100, 100 );
2899     check_update_rgn( hwnd, hrgn );
2900
2901     flush_sequence();
2902     SetRectRgn( hrgn, 0, 0, 100, 100 );
2903     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
2904     SetRectRgn( hrgn, 0, 0, 50, 50 );
2905     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
2906     ok_sequence( WmPaint, "Paint", FALSE );
2907
2908     flush_sequence();
2909     SetRectRgn( hrgn, -4, -4, -2, -2 );
2910     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
2911     SetRectRgn( hrgn, -4, -4, -3, -3 );
2912     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
2913     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
2914
2915     flush_sequence();
2916     SetRectRgn( hrgn, -4, -4, -2, -2 );
2917     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
2918     SetRectRgn( hrgn, -4, -4, -3, -3 );
2919     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
2920     SetRectRgn( hrgn, 0, 0, 1, 1 );
2921     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
2922     ok_sequence( WmPaint, "Paint", TRUE );
2923
2924     flush_sequence();
2925     SetRectRgn( hrgn, -4, -4, -1, -1 );
2926     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
2927     RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
2928     /* make sure no WM_PAINT was generated */
2929     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
2930     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
2931
2932     flush_sequence();
2933     SetRectRgn( hrgn, -4, -4, -1, -1 );
2934     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
2935     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
2936     {
2937         if (msg.hwnd == hwnd && msg.message == WM_PAINT)
2938         {
2939             /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
2940             INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
2941             ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
2942             ret = GetUpdateRect( hwnd, &rect, FALSE );
2943             ok( ret, "Invalid GetUpdateRect result %d\n", ret );
2944             /* this will send WM_NCPAINT and validate the non client area */
2945             ret = GetUpdateRect( hwnd, &rect, TRUE );
2946             ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
2947         }
2948         else DispatchMessage( &msg );
2949     }
2950     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
2951
2952     DeleteObject( hrgn );
2953     DeleteObject( hrgn2 );
2954     DestroyWindow( hwnd );
2955 }
2956
2957 struct wnd_event
2958 {
2959     HWND hwnd;
2960     HANDLE event;
2961 };
2962
2963 static DWORD WINAPI thread_proc(void *param)
2964 {
2965     MSG msg;
2966     struct wnd_event *wnd_event = (struct wnd_event *)param;
2967
2968     wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
2969                                       100, 100, 200, 200, 0, 0, 0, NULL);
2970     ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
2971
2972     SetEvent(wnd_event->event);
2973
2974     while (GetMessage(&msg, 0, 0, 0))
2975     {
2976         TranslateMessage(&msg);
2977         DispatchMessage(&msg);
2978     }
2979
2980     return 0;
2981 }
2982
2983 static void test_interthread_messages(void)
2984 {
2985     HANDLE hThread;
2986     DWORD tid;
2987     WNDPROC proc;
2988     MSG msg;
2989     char buf[256];
2990     int len, expected_len;
2991     struct wnd_event wnd_event;
2992
2993     wnd_event.event = CreateEventW(NULL, 0, 0, NULL);
2994     if (!wnd_event.event)
2995     {
2996         trace("skipping interthread message test under win9x\n");
2997         return;
2998     }
2999
3000     hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
3001     ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError());
3002
3003     ok(WaitForSingleObject(wnd_event.event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
3004
3005     CloseHandle(wnd_event.event);
3006
3007     SetLastError(0xdeadbeef);
3008     ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeded\n");
3009     ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error code %ld\n", GetLastError());
3010
3011     proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
3012     ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %ld\n", GetLastError());
3013
3014     expected_len = lstrlenA("window caption text");
3015     memset(buf, 0, sizeof(buf));
3016     SetLastError(0xdeadbeef);
3017     len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
3018     ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %ld, len %d, expected len %d\n", GetLastError(), len, expected_len);
3019     ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
3020
3021     msg.hwnd = wnd_event.hwnd;
3022     msg.message = WM_GETTEXT;
3023     msg.wParam = sizeof(buf);
3024     msg.lParam = (LPARAM)buf;
3025     memset(buf, 0, sizeof(buf));
3026     SetLastError(0xdeadbeef);
3027     len = DispatchMessageA(&msg);
3028     ok(!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3029        "DispatchMessageA(WM_GETTEXT) succeded on another thread window: ret %d, error %ld\n", len, GetLastError());
3030
3031     /* the following test causes an exception in user.exe under win9x */
3032     msg.hwnd = wnd_event.hwnd;
3033     msg.message = WM_TIMER;
3034     msg.wParam = 0;
3035     msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
3036     SetLastError(0xdeadbeef);
3037     len = DispatchMessageA(&msg);
3038     ok(!len && GetLastError() == 0xdeadbeef,
3039        "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %ld\n", len, GetLastError());
3040
3041     ok(PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0), "PostMessageA(WM_QUIT) error %ld\n", GetLastError());
3042
3043     ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
3044     CloseHandle(hThread);
3045 }
3046
3047
3048 static const struct message WmVkN[] = {
3049     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
3050     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
3051     { WM_CHAR, wparam|lparam, 'n', 1 },
3052     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
3053     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
3054     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
3055     { 0 }
3056 };
3057 static const struct message WmShiftVkN[] = {
3058     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
3059     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
3060     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
3061     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
3062     { WM_CHAR, wparam|lparam, 'N', 1 },
3063     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
3064     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
3065     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
3066     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
3067     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
3068     { 0 }
3069 };
3070 static const struct message WmCtrlVkN[] = {
3071     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
3072     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
3073     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
3074     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
3075     { WM_CHAR, wparam|lparam, 0x000e, 1 },
3076     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
3077     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
3078     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
3079     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
3080     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
3081     { 0 }
3082 };
3083 static const struct message WmCtrlVkN_2[] = {
3084     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
3085     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
3086     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
3087     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
3088     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
3089     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
3090     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
3091     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
3092     { 0 }
3093 };
3094 static const struct message WmAltVkN[] = {
3095     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
3096     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
3097     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
3098     { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
3099     { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
3100     { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
3101     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
3102     { HCBT_SYSCOMMAND, hook },
3103     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
3104     { WM_SETCURSOR, sent|defwinproc },
3105     { WM_INITMENU, sent|defwinproc },
3106     { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
3107     { WM_CAPTURECHANGED, sent|defwinproc },
3108     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
3109     { WM_EXITMENULOOP, sent|defwinproc },
3110     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
3111     { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
3112     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
3113     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
3114     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
3115     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
3116     { 0 }
3117 };
3118 static const struct message WmAltVkN_2[] = {
3119     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
3120     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
3121     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
3122     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
3123     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
3124     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
3125     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
3126     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
3127     { 0 }
3128 };
3129 static const struct message WmCtrlAltVkN[] = {
3130     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
3131     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
3132     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
3133     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
3134     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
3135     { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
3136     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
3137     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
3138     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
3139     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
3140     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
3141     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
3142     { 0 }
3143 };
3144
3145 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
3146 {
3147     MSG msg;
3148
3149     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
3150     {
3151         struct message log_msg;
3152
3153         trace("accel: %p, %04x, %08x, %08lx\n", msg.hwnd, msg.message, msg.wParam, msg.lParam);
3154
3155         log_msg.message = msg.message;
3156         log_msg.flags = wparam|lparam;
3157         log_msg.wParam = msg.wParam;
3158         log_msg.lParam = msg.lParam;
3159         add_message(&log_msg);
3160
3161         if (!TranslateAccelerator(hwnd, hAccel, &msg))
3162         {
3163             TranslateMessage(&msg);
3164             DispatchMessage(&msg);
3165         }
3166     }
3167 }
3168
3169 static void test_accelerators(void)
3170 {
3171     SHORT state;
3172     HACCEL hAccel;
3173     HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
3174                                 100, 100, 200, 200, 0, 0, 0, NULL);
3175     assert(hwnd != 0);
3176
3177     SetFocus(hwnd);
3178     ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
3179
3180     state = GetKeyState(VK_SHIFT);
3181     ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
3182     state = GetKeyState(VK_CAPITAL);
3183     ok(state == 0, "wrong CapsLock state %04x\n", state);
3184
3185     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(1));
3186     assert(hAccel != 0);
3187
3188     trace("testing VK_N press/release\n");
3189     flush_sequence();
3190     keybd_event('N', 0, 0, 0);
3191     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3192     pump_msg_loop(hwnd, hAccel);
3193     ok_sequence(WmVkN, "VK_N press/release", FALSE);
3194
3195     trace("testing Shift+VK_N press/release\n");
3196     flush_sequence();
3197     keybd_event(VK_SHIFT, 0, 0, 0);
3198     keybd_event('N', 0, 0, 0);
3199     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3200     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
3201     pump_msg_loop(hwnd, hAccel);
3202     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
3203
3204     trace("testing Ctrl+VK_N press/release\n");
3205     flush_sequence();
3206     keybd_event(VK_CONTROL, 0, 0, 0);
3207     keybd_event('N', 0, 0, 0);
3208     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3209     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
3210     pump_msg_loop(hwnd, hAccel);
3211     ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
3212
3213     trace("testing Alt+VK_N press/release\n");
3214     flush_sequence();
3215     keybd_event(VK_MENU, 0, 0, 0);
3216     keybd_event('N', 0, 0, 0);
3217     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3218     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
3219     pump_msg_loop(hwnd, hAccel);
3220     ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
3221
3222     trace("testing Ctrl+Alt+VK_N press/release\n");
3223     flush_sequence();
3224     keybd_event(VK_CONTROL, 0, 0, 0);
3225     keybd_event(VK_MENU, 0, 0, 0);
3226     keybd_event('N', 0, 0, 0);
3227     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3228     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
3229     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
3230     pump_msg_loop(hwnd, hAccel);
3231     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
3232
3233     ok(DestroyAcceleratorTable(hAccel), "DestroyAcceleratorTable error %ld\n", GetLastError());
3234
3235     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(2));
3236     assert(hAccel != 0);
3237
3238     trace("testing VK_N press/release\n");
3239     flush_sequence();
3240     keybd_event('N', 0, 0, 0);
3241     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3242     pump_msg_loop(hwnd, hAccel);
3243     ok_sequence(WmVkN, "VK_N press/release", FALSE);
3244
3245     trace("testing Shift+VK_N press/release\n");
3246     flush_sequence();
3247     keybd_event(VK_SHIFT, 0, 0, 0);
3248     keybd_event('N', 0, 0, 0);
3249     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3250     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
3251     pump_msg_loop(hwnd, hAccel);
3252     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
3253
3254     trace("testing Ctrl+VK_N press/release 2\n");
3255     flush_sequence();
3256     keybd_event(VK_CONTROL, 0, 0, 0);
3257     keybd_event('N', 0, 0, 0);
3258     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3259     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
3260     pump_msg_loop(hwnd, hAccel);
3261     ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
3262
3263     trace("testing Alt+VK_N press/release 2\n");
3264     flush_sequence();
3265     keybd_event(VK_MENU, 0, 0, 0);
3266     keybd_event('N', 0, 0, 0);
3267     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3268     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
3269     pump_msg_loop(hwnd, hAccel);
3270     ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
3271
3272     trace("testing Ctrl+Alt+VK_N press/release\n");
3273     flush_sequence();
3274     keybd_event(VK_CONTROL, 0, 0, 0);
3275     keybd_event(VK_MENU, 0, 0, 0);
3276     keybd_event('N', 0, 0, 0);
3277     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3278     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
3279     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
3280     pump_msg_loop(hwnd, hAccel);
3281     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
3282
3283     ok(DestroyAcceleratorTable(hAccel), "DestroyAcceleratorTable error %ld\n", GetLastError());
3284
3285     DestroyWindow(hwnd);
3286 }
3287
3288 /************* window procedures ********************/
3289
3290 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3291 {
3292     static long defwndproc_counter = 0;
3293     static long beginpaint_counter = 0;
3294     LRESULT ret;
3295     struct message msg;
3296
3297     trace("%p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
3298
3299     switch (message)
3300     {
3301         case WM_WINDOWPOSCHANGING:
3302         case WM_WINDOWPOSCHANGED:
3303         {
3304             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
3305
3306             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
3307             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
3308                   winpos->hwnd, winpos->hwndInsertAfter,
3309                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
3310
3311             /* Log only documented flags, win2k uses 0x1000 and 0x2000
3312              * in the high word for internal purposes
3313              */
3314             wParam = winpos->flags & 0xffff;
3315             break;
3316         }
3317     }
3318
3319     msg.message = message;
3320     msg.flags = sent|wparam|lparam;
3321     if (defwndproc_counter) msg.flags |= defwinproc;
3322     if (beginpaint_counter) msg.flags |= beginpaint;
3323     msg.wParam = wParam;
3324     msg.lParam = lParam;
3325     add_message(&msg);
3326
3327     if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
3328     {
3329         HWND parent = GetParent(hwnd);
3330         RECT rc;
3331         MINMAXINFO *minmax = (MINMAXINFO *)lParam;
3332
3333         GetClientRect(parent, &rc);
3334         trace("parent %p client size = (%ld x %ld)\n", parent, rc.right, rc.bottom);
3335
3336         trace("ptReserved = (%ld,%ld)\n"
3337               "ptMaxSize = (%ld,%ld)\n"
3338               "ptMaxPosition = (%ld,%ld)\n"
3339               "ptMinTrackSize = (%ld,%ld)\n"
3340               "ptMaxTrackSize = (%ld,%ld)\n",
3341               minmax->ptReserved.x, minmax->ptReserved.y,
3342               minmax->ptMaxSize.x, minmax->ptMaxSize.y,
3343               minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
3344               minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
3345               minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
3346
3347         ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %ld != %ld\n",
3348            minmax->ptMaxSize.x, rc.right);
3349         ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %ld != %ld\n",
3350            minmax->ptMaxSize.y, rc.bottom);
3351     }
3352
3353     if (message == WM_PAINT)
3354     {
3355         PAINTSTRUCT ps;
3356         beginpaint_counter++;
3357         BeginPaint( hwnd, &ps );
3358         beginpaint_counter--;
3359         EndPaint( hwnd, &ps );
3360         return 0;
3361     }
3362
3363     defwndproc_counter++;
3364     ret = DefWindowProcA(hwnd, message, wParam, lParam);
3365     defwndproc_counter--;
3366
3367     return ret;
3368 }
3369
3370 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3371 {
3372     static long defwndproc_counter = 0;
3373     LRESULT ret;
3374     struct message msg;
3375
3376     trace("popup: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
3377
3378     msg.message = message;
3379     msg.flags = sent|wparam|lparam;
3380     if (defwndproc_counter) msg.flags |= defwinproc;
3381     msg.wParam = wParam;
3382     msg.lParam = lParam;
3383     add_message(&msg);
3384
3385     if (message == WM_CREATE)
3386     {
3387         DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
3388         SetWindowLongA(hwnd, GWL_STYLE, style);
3389     }
3390
3391     defwndproc_counter++;
3392     ret = DefWindowProcA(hwnd, message, wParam, lParam);
3393     defwndproc_counter--;
3394
3395     return ret;
3396 }
3397
3398 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3399 {
3400     static long defwndproc_counter = 0;
3401     LRESULT ret;
3402     struct message msg;
3403
3404     trace("parent: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
3405
3406     if (message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
3407         message == WM_SETFOCUS || message == WM_KILLFOCUS ||
3408         message == WM_ENABLE || message == WM_ENTERIDLE ||
3409         message == WM_IME_SETCONTEXT)
3410     {
3411         msg.message = message;
3412         msg.flags = sent|parent|wparam|lparam;
3413         if (defwndproc_counter) msg.flags |= defwinproc;
3414         msg.wParam = wParam;
3415         msg.lParam = lParam;
3416         add_message(&msg);
3417     }
3418
3419     defwndproc_counter++;
3420     ret = DefWindowProcA(hwnd, message, wParam, lParam);
3421     defwndproc_counter--;
3422
3423     return ret;
3424 }
3425
3426 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3427 {
3428     static long defwndproc_counter = 0;
3429     LRESULT ret;
3430     struct message msg;
3431
3432     trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
3433
3434     DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
3435     ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
3436     if (after_end_dialog)
3437         ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
3438     else
3439         ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
3440
3441     msg.message = message;
3442     msg.flags = sent|wparam|lparam;
3443     if (defwndproc_counter) msg.flags |= defwinproc;
3444     msg.wParam = wParam;
3445     msg.lParam = lParam;
3446     add_message(&msg);
3447
3448     defwndproc_counter++;
3449     ret = DefDlgProcA(hwnd, message, wParam, lParam);
3450     defwndproc_counter--;
3451
3452     return ret;
3453 }
3454
3455 static BOOL RegisterWindowClasses(void)
3456 {
3457     WNDCLASSA cls;
3458
3459     cls.style = 0;
3460     cls.lpfnWndProc = MsgCheckProcA;
3461     cls.cbClsExtra = 0;
3462     cls.cbWndExtra = 0;
3463     cls.hInstance = GetModuleHandleA(0);
3464     cls.hIcon = 0;
3465     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
3466     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
3467     cls.lpszMenuName = NULL;
3468     cls.lpszClassName = "TestWindowClass";
3469     if(!RegisterClassA(&cls)) return FALSE;
3470
3471     cls.lpfnWndProc = PopupMsgCheckProcA;
3472     cls.lpszClassName = "TestPopupClass";
3473     if(!RegisterClassA(&cls)) return FALSE;
3474
3475     cls.lpfnWndProc = ParentMsgCheckProcA;
3476     cls.lpszClassName = "TestParentClass";
3477     if(!RegisterClassA(&cls)) return FALSE;
3478
3479     cls.lpfnWndProc = DefWindowProcA;
3480     cls.lpszClassName = "SimpleWindowClass";
3481     if(!RegisterClassA(&cls)) return FALSE;
3482
3483     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
3484     cls.lpfnWndProc = TestDlgProcA;
3485     cls.lpszClassName = "TestDialogClass";
3486     if(!RegisterClassA(&cls)) return FALSE;
3487
3488     return TRUE;
3489 }
3490
3491 static HHOOK hCBT_hook;
3492
3493 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
3494
3495     char buf[256];
3496
3497     trace("CBT: %d, %08x, %08lx\n", nCode, wParam, lParam);
3498
3499     if (nCode == HCBT_SYSCOMMAND)
3500     {
3501         struct message msg;
3502
3503         msg.message = nCode;
3504         msg.flags = hook;
3505         msg.wParam = wParam;
3506         msg.lParam = lParam;
3507         add_message(&msg);
3508
3509         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
3510     }
3511
3512     /* Log also SetFocus(0) calls */
3513     if (!wParam) wParam = lParam;
3514
3515     if (GetClassNameA((HWND)wParam, buf, sizeof(buf)))
3516     {
3517         if (!strcmp(buf, "TestWindowClass") ||
3518             !strcmp(buf, "TestParentClass") ||
3519             !strcmp(buf, "TestPopupClass") ||
3520             !strcmp(buf, "SimpleWindowClass") ||
3521             !strcmp(buf, "TestDialogClass") ||
3522             !strcmp(buf, "MDI_frame_class") ||
3523             !strcmp(buf, "MDI_client_class") ||
3524             !strcmp(buf, "MDI_child_class") ||
3525             !strcmp(buf, "my_button_class") ||
3526             !strcmp(buf, "#32770"))
3527         {
3528             struct message msg;
3529
3530             msg.message = nCode;
3531             msg.flags = hook;
3532             msg.wParam = wParam;
3533             msg.lParam = lParam;
3534             add_message(&msg);
3535         }
3536     }
3537     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
3538 }
3539
3540 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
3541 static const WCHAR wszAnsi[] = {'U',0};
3542
3543 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
3544 {
3545     switch (uMsg)
3546     {
3547     case CB_FINDSTRINGEXACT:
3548         trace("String: %p\n", (LPCWSTR)lParam);
3549         if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
3550             return 1;
3551         if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
3552             return 0;
3553         return -1;
3554     }
3555     return DefWindowProcW(hwnd, uMsg, wParam, lParam);
3556 }
3557
3558 static void test_message_conversion(void)
3559 {
3560     static const WCHAR wszMsgConversionClass[] =
3561         {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
3562     WNDCLASSW cls;
3563     LRESULT lRes;
3564     HWND hwnd;
3565     WNDPROC wndproc;
3566
3567     cls.style = 0;
3568     cls.lpfnWndProc = MsgConversionProcW;
3569     cls.cbClsExtra = 0;
3570     cls.cbWndExtra = 0;
3571     cls.hInstance = GetModuleHandleW(NULL);
3572     cls.hIcon = NULL;
3573     cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
3574     cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
3575     cls.lpszMenuName = NULL;
3576     cls.lpszClassName = wszMsgConversionClass;
3577     /* this call will fail on Win9x, but that doesn't matter as this test is
3578      * meaningless on those platforms */
3579     if(!RegisterClassW(&cls)) return;
3580
3581     hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
3582                            100, 100, 200, 200, 0, 0, 0, NULL);
3583     ok(hwnd != NULL, "Window creation failed\n");
3584
3585     /* {W, A} -> A */
3586
3587     wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
3588     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3589     ok(lRes == 0, "String should have been converted\n");
3590     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3591     ok(lRes == 1, "String shouldn't have been converted\n");
3592
3593     /* {W, A} -> W */
3594
3595     wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
3596     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3597     ok(lRes == 1, "String shouldn't have been converted\n");
3598     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3599     ok(lRes == 1, "String shouldn't have been converted\n");
3600
3601     /* Synchronous messages */
3602
3603     lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3604     ok(lRes == 0, "String should have been converted\n");
3605     lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3606     ok(lRes == 1, "String shouldn't have been converted\n");
3607
3608     /* Asynchronous messages */
3609
3610     SetLastError(0);
3611     lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3612     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3613         "PostMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3614     SetLastError(0);
3615     lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3616     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3617         "PostMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3618     SetLastError(0);
3619     lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3620     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3621         "PosThreadtMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3622     SetLastError(0);
3623     lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3624     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3625         "PosThreadtMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3626     SetLastError(0);
3627     lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3628     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3629         "SendNotifyMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3630     SetLastError(0);
3631     lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3632     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3633         "SendNotifyMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3634     SetLastError(0);
3635     lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
3636     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3637         "SendMessageCallback on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3638     SetLastError(0);
3639     lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
3640     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3641         "SendMessageCallback on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3642 }
3643
3644 START_TEST(msg)
3645 {
3646     if (!RegisterWindowClasses()) assert(0);
3647
3648     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
3649     assert(hCBT_hook);
3650
3651     test_messages();
3652     test_mdi_messages();
3653     test_button_messages();
3654     test_paint_messages();
3655     test_interthread_messages();
3656     test_message_conversion();
3657     test_accelerators();
3658
3659     UnhookWindowsHookEx(hCBT_hook);
3660 }