Added a test case for inter-thread DispatchMessage.
[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_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
1206 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
1207     { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
1208     { HCBT_SYSCOMMAND, hook },
1209     { WM_CLOSE, sent|defwinproc },
1210     { WM_MDIDESTROY, sent }, /* in MDI client */
1211
1212     /* bring the 1st MDI child to top */
1213     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
1214     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
1215     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
1216     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
1217     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
1218
1219     /* maximize the 1st MDI child */
1220     { HCBT_MINMAX, hook },
1221     { WM_GETMINMAXINFO, sent|defwinproc },
1222     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|0x8000 },
1223     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
1224     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
1225     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1226     { WM_SIZE, sent|defwinproc },
1227
1228     /* restore the 2nd MDI child */
1229     { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
1230     { HCBT_MINMAX, hook },
1231     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOZORDER|0x8000 },
1232     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
1233     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1234     { WM_SIZE, sent|defwinproc },
1235     { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
1236      /* in MDI frame */
1237     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1238     { WM_NCCALCSIZE, sent|wparam, 1 },
1239     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1240
1241     /* bring the 1st MDI child to top */
1242     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1243     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1244     { HCBT_SETFOCUS, hook },
1245     { WM_KILLFOCUS, sent|defwinproc },
1246     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
1247     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1248     { WM_SETFOCUS, sent }, /* in MDI client */
1249     { HCBT_SETFOCUS, hook },
1250     { WM_KILLFOCUS, sent }, /* in MDI client */
1251     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1252     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1253     { WM_SETFOCUS, sent|defwinproc },
1254     { WM_MDIACTIVATE, sent|defwinproc },
1255     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1256
1257     /* apparently ShowWindow(SW_SHOW) on an MDI client */
1258     { WM_SHOWWINDOW, sent|wparam, 1 },
1259     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1260     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1261     { WM_MDIREFRESHMENU, sent },
1262
1263     { HCBT_DESTROYWND, hook },
1264     /* Win2k sends wparam set to
1265      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1266      * while Win9x doesn't bother to set child window id according to
1267      * CLIENTCREATESTRUCT.idFirstChild
1268      */
1269     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1270     { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
1271     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1272     { WM_ERASEBKGND, sent|parent|optional },
1273     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1274
1275     { WM_DESTROY, sent|defwinproc },
1276     { WM_NCDESTROY, sent|defwinproc },
1277     { 0 }
1278 };
1279 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
1280 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
1281     { HCBT_MINMAX, hook },
1282     { WM_GETMINMAXINFO, sent },
1283     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
1284     { WM_NCCALCSIZE, sent|wparam, 1 },
1285     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1286
1287     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1288     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1289     { HCBT_SETFOCUS, hook },
1290     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1291     { WM_SETFOCUS, sent }, /* in MDI client */
1292     { HCBT_SETFOCUS, hook },
1293     { WM_KILLFOCUS, sent }, /* in MDI client */
1294     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1295     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1296     { WM_SETFOCUS, sent|defwinproc },
1297     { WM_MDIACTIVATE, sent|defwinproc },
1298     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1299     { WM_SIZE, sent|defwinproc },
1300      /* in MDI frame */
1301     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1302     { WM_NCCALCSIZE, sent|wparam, 1 },
1303     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1304     { 0 }
1305 };
1306 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
1307 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
1308     { HCBT_MINMAX, hook },
1309     { WM_GETMINMAXINFO, sent },
1310     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
1311     { WM_NCCALCSIZE, sent|wparam, 1 },
1312     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1313     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1314     { WM_SIZE, sent|defwinproc },
1315      /* in MDI frame */
1316     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1317     { WM_NCCALCSIZE, sent|wparam, 1 },
1318     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1319     { 0 }
1320 };
1321 /* ShowWindow(SW_RESTORE) for a visible MDI child window */
1322 static const struct message WmRestoreMDIchildVisibleSeq[] = {
1323     { HCBT_MINMAX, hook },
1324     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
1325     { WM_NCCALCSIZE, sent|wparam, 1 },
1326     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1327     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1328     { WM_SIZE, sent|defwinproc },
1329      /* in MDI frame */
1330     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1331     { WM_NCCALCSIZE, sent|wparam, 1 },
1332     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1333     { 0 }
1334 };
1335 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
1336 static const struct message WmRestoreMDIchildInisibleSeq[] = {
1337     { HCBT_MINMAX, hook },
1338     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
1339     { WM_NCCALCSIZE, sent|wparam, 1 },
1340     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1341     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1342     { WM_SIZE, sent|defwinproc },
1343      /* in MDI frame */
1344     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1345     { WM_NCCALCSIZE, sent|wparam, 1 },
1346     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1347     { 0 }
1348 };
1349
1350 static HWND mdi_client;
1351 static WNDPROC old_mdi_client_proc;
1352
1353 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1354 {
1355     struct message msg;
1356
1357     /* do not log painting messages */
1358     if (message != WM_PAINT &&
1359         message != WM_ERASEBKGND &&
1360         message != WM_NCPAINT &&
1361         message != WM_GETTEXT)
1362     {
1363         trace("mdi client: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1364
1365         switch (message)
1366         {
1367             case WM_WINDOWPOSCHANGING:
1368             case WM_WINDOWPOSCHANGED:
1369             {
1370                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
1371
1372                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
1373                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
1374                       winpos->hwnd, winpos->hwndInsertAfter,
1375                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
1376
1377                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
1378                  * in the high word for internal purposes
1379                  */
1380                 wParam = winpos->flags & 0xffff;
1381                 break;
1382             }
1383         }
1384
1385         msg.message = message;
1386         msg.flags = sent|wparam|lparam;
1387         msg.wParam = wParam;
1388         msg.lParam = lParam;
1389         add_message(&msg);
1390     }
1391
1392     return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
1393 }
1394
1395 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1396 {
1397     static long defwndproc_counter = 0;
1398     LRESULT ret;
1399     struct message msg;
1400
1401     /* do not log painting messages */
1402     if (message != WM_PAINT &&
1403         message != WM_ERASEBKGND &&
1404         message != WM_NCPAINT &&
1405         message != WM_GETTEXT)
1406     {
1407         trace("mdi child: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1408
1409         switch (message)
1410         {
1411             case WM_WINDOWPOSCHANGING:
1412             case WM_WINDOWPOSCHANGED:
1413             {
1414                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
1415
1416                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
1417                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
1418                       winpos->hwnd, winpos->hwndInsertAfter,
1419                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
1420
1421                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
1422                  * in the high word for internal purposes
1423                  */
1424                 wParam = winpos->flags & 0xffff;
1425                 break;
1426             }
1427         }
1428
1429         msg.message = message;
1430         msg.flags = sent|wparam|lparam;
1431         if (defwndproc_counter) msg.flags |= defwinproc;
1432         msg.wParam = wParam;
1433         msg.lParam = lParam;
1434         add_message(&msg);
1435     }
1436
1437     defwndproc_counter++;
1438     ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
1439     defwndproc_counter--;
1440
1441     return ret;
1442 }
1443
1444 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1445 {
1446     static long defwndproc_counter = 0;
1447     LRESULT ret;
1448     struct message msg;
1449
1450     /* do not log painting messages */
1451     if (message != WM_PAINT &&
1452         message != WM_ERASEBKGND &&
1453         message != WM_NCPAINT &&
1454         message != WM_GETTEXT)
1455     {
1456         trace("mdi frame: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1457
1458         switch (message)
1459         {
1460             case WM_WINDOWPOSCHANGING:
1461             case WM_WINDOWPOSCHANGED:
1462             {
1463                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
1464
1465                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
1466                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
1467                       winpos->hwnd, winpos->hwndInsertAfter,
1468                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
1469
1470                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
1471                  * in the high word for internal purposes
1472                  */
1473                 wParam = winpos->flags & 0xffff;
1474                 break;
1475             }
1476         }
1477
1478         msg.message = message;
1479         msg.flags = sent|wparam|lparam;
1480         if (defwndproc_counter) msg.flags |= defwinproc;
1481         msg.wParam = wParam;
1482         msg.lParam = lParam;
1483         add_message(&msg);
1484     }
1485
1486     defwndproc_counter++;
1487     ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
1488     defwndproc_counter--;
1489
1490     return ret;
1491 }
1492
1493 static BOOL mdi_RegisterWindowClasses(void)
1494 {
1495     WNDCLASSA cls;
1496
1497     cls.style = 0;
1498     cls.lpfnWndProc = mdi_frame_wnd_proc;
1499     cls.cbClsExtra = 0;
1500     cls.cbWndExtra = 0;
1501     cls.hInstance = GetModuleHandleA(0);
1502     cls.hIcon = 0;
1503     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
1504     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
1505     cls.lpszMenuName = NULL;
1506     cls.lpszClassName = "MDI_frame_class";
1507     if (!RegisterClassA(&cls)) return FALSE;
1508
1509     cls.lpfnWndProc = mdi_child_wnd_proc;
1510     cls.lpszClassName = "MDI_child_class";
1511     if (!RegisterClassA(&cls)) return FALSE;
1512
1513     if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
1514     old_mdi_client_proc = cls.lpfnWndProc;
1515     cls.hInstance = GetModuleHandleA(0);
1516     cls.lpfnWndProc = mdi_client_hook_proc;
1517     cls.lpszClassName = "MDI_client_class";
1518     if (!RegisterClassA(&cls)) assert(0);
1519
1520     return TRUE;
1521 }
1522
1523 static void test_mdi_messages(void)
1524 {
1525     MDICREATESTRUCTA mdi_cs;
1526     CLIENTCREATESTRUCT client_cs;
1527     HWND mdi_frame, mdi_child, mdi_child2, active_child;
1528     BOOL zoomed;
1529
1530     assert(mdi_RegisterWindowClasses());
1531
1532     flush_sequence();
1533
1534     trace("creating MDI frame window\n");
1535     mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
1536                                 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
1537                                 WS_MAXIMIZEBOX | WS_VISIBLE,
1538                                 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
1539                                 GetDesktopWindow(), 0,
1540                                 GetModuleHandleA(0), NULL);
1541     assert(mdi_frame);
1542     ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", TRUE);
1543
1544     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1545     ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
1546
1547     trace("creating MDI client window\n");
1548     client_cs.hWindowMenu = 0;
1549     client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
1550     mdi_client = CreateWindowExA(0, "MDI_client_class",
1551                                  NULL,
1552                                  WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
1553                                  0, 0, 0, 0,
1554                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
1555     assert(mdi_client);
1556     ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
1557
1558     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1559     ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
1560
1561     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1562     ok(!active_child, "wrong active MDI child %p\n", active_child);
1563     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
1564
1565     SetFocus(0);
1566     flush_sequence();
1567
1568     trace("creating visible MDI child window\n");
1569     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
1570                                 WS_CHILD | WS_VISIBLE,
1571                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
1572                                 mdi_client, 0, GetModuleHandleA(0), NULL);
1573     assert(mdi_child);
1574     ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", TRUE);
1575
1576     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
1577     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
1578
1579     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1580     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
1581
1582     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1583     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
1584     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
1585     flush_sequence();
1586
1587     DestroyWindow(mdi_child);
1588     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
1589
1590     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1591     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1592
1593     /* Win2k: MDI client still returns a just destroyed child as active
1594      * Win9x: MDI client returns 0
1595      */
1596     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1597     ok(active_child == mdi_child || /* win2k */
1598        !active_child, /* win9x */
1599        "wrong active MDI child %p\n", active_child);
1600     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
1601
1602     flush_sequence();
1603
1604     trace("creating invisible MDI child window\n");
1605     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
1606                                 WS_CHILD,
1607                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
1608                                 mdi_client, 0, GetModuleHandleA(0), NULL);
1609     assert(mdi_child2);
1610     ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
1611
1612     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
1613     ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
1614
1615     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1616     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1617
1618     /* Win2k: MDI client still returns a just destroyed child as active
1619      * Win9x: MDI client returns mdi_child2
1620      */
1621     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1622     ok(active_child == mdi_child || /* win2k */
1623        active_child == mdi_child2, /* win9x */
1624        "wrong active MDI child %p\n", active_child);
1625     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
1626     flush_sequence();
1627
1628     ShowWindow(mdi_child2, SW_MAXIMIZE);
1629     ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", TRUE);
1630
1631     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
1632     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
1633
1634     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1635     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
1636     ok(zoomed, "wrong zoomed state %d\n", zoomed);
1637     flush_sequence();
1638
1639     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1640     ok(GetFocus() == mdi_child2 || /* win2k */
1641        GetFocus() == 0, /* win9x */
1642        "wrong focus window %p\n", GetFocus());
1643
1644     SetFocus(0);
1645     flush_sequence();
1646
1647     ShowWindow(mdi_child2, SW_HIDE);
1648     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
1649
1650     ShowWindow(mdi_child2, SW_RESTORE);
1651     ok_sequence(WmRestoreMDIchildInisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", TRUE);
1652     flush_sequence();
1653
1654     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
1655     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
1656
1657     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1658     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
1659     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
1660     flush_sequence();
1661
1662     SetFocus(0);
1663     flush_sequence();
1664
1665     ShowWindow(mdi_child2, SW_HIDE);
1666     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
1667
1668     ShowWindow(mdi_child2, SW_SHOW);
1669     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", TRUE);
1670
1671     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1672     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1673
1674     ShowWindow(mdi_child2, SW_MAXIMIZE);
1675     ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", TRUE);
1676
1677     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1678     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1679
1680     ShowWindow(mdi_child2, SW_RESTORE);
1681     ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):MDI child", TRUE);
1682
1683     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1684     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1685
1686     SetFocus(0);
1687     flush_sequence();
1688
1689     ShowWindow(mdi_child2, SW_HIDE);
1690     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
1691
1692     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1693     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1694
1695     DestroyWindow(mdi_child2);
1696     ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", TRUE);
1697
1698     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1699     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1700
1701     /* test for maximized MDI children */
1702     trace("creating maximized visible MDI child window 1\n");
1703     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
1704                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
1705                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
1706                                 mdi_client, 0, GetModuleHandleA(0), NULL);
1707     assert(mdi_child);
1708     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
1709     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
1710
1711     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1712     ok(GetFocus() == mdi_child || /* win2k */
1713        GetFocus() == 0, /* win9x */
1714        "wrong focus window %p\n", GetFocus());
1715
1716     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1717     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
1718     ok(zoomed, "wrong zoomed state %d\n", zoomed);
1719     flush_sequence();
1720
1721     trace("creating maximized visible MDI child window 2\n");
1722     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
1723                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
1724                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
1725                                 mdi_client, 0, GetModuleHandleA(0), NULL);
1726     assert(mdi_child2);
1727     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
1728     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
1729     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
1730
1731     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1732     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
1733
1734     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1735     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
1736     ok(zoomed, "wrong zoomed state %d\n", zoomed);
1737     flush_sequence();
1738
1739     trace("destroying maximized visible MDI child window 2\n");
1740     DestroyWindow(mdi_child2);
1741     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
1742
1743     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
1744
1745     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1746     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1747
1748     /* Win2k: MDI client still returns a just destroyed child as active
1749      * Win9x: MDI client returns 0
1750      */
1751     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1752     ok(active_child == mdi_child2 || /* win2k */
1753        !active_child, /* win9x */
1754        "wrong active MDI child %p\n", active_child);
1755     flush_sequence();
1756
1757     ShowWindow(mdi_child, SW_MAXIMIZE);
1758     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
1759     flush_sequence();
1760
1761     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1762     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
1763
1764     trace("re-creating maximized visible MDI child window 2\n");
1765     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
1766                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
1767                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
1768                                 mdi_client, 0, GetModuleHandleA(0), NULL);
1769     assert(mdi_child2);
1770     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
1771     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
1772     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
1773
1774     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1775     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
1776
1777     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1778     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
1779     ok(zoomed, "wrong zoomed state %d\n", zoomed);
1780     flush_sequence();
1781
1782     SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
1783     ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
1784     ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
1785
1786     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
1787     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1788     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
1789
1790     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1791     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
1792     ok(zoomed, "wrong zoomed state %d\n", zoomed);
1793     flush_sequence();
1794
1795     DestroyWindow(mdi_child);
1796     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
1797
1798     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1799     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1800
1801     /* Win2k: MDI client still returns a just destroyed child as active
1802      * Win9x: MDI client returns 0
1803      */
1804     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1805     ok(active_child == mdi_child || /* win2k */
1806        !active_child, /* win9x */
1807        "wrong active MDI child %p\n", active_child);
1808     flush_sequence();
1809     /* end of test for maximized MDI children */
1810
1811     mdi_cs.szClass = "MDI_child_Class";
1812     mdi_cs.szTitle = "MDI child";
1813     mdi_cs.hOwner = GetModuleHandleA(0);
1814     mdi_cs.x = CW_USEDEFAULT;
1815     mdi_cs.y = CW_USEDEFAULT;
1816     mdi_cs.cx = CW_USEDEFAULT;
1817     mdi_cs.cy = CW_USEDEFAULT;
1818     mdi_cs.style = WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX;
1819     mdi_cs.lParam = 0;
1820     mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
1821     ok(mdi_child != 0, "MDI child creation failed\n");
1822
1823     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1824     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
1825
1826     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
1827     ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
1828     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1829     ok(!active_child, "wrong active MDI child %p\n", active_child);
1830
1831     SetFocus(0);
1832     flush_sequence();
1833
1834     DestroyWindow(mdi_client);
1835     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
1836
1837     DestroyWindow(mdi_frame);
1838     ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
1839 }
1840 /************************* End of MDI test **********************************/
1841
1842 static void test_WM_SETREDRAW(HWND hwnd)
1843 {
1844     DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
1845
1846     flush_sequence();
1847
1848     SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
1849     ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
1850
1851     ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
1852     ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
1853
1854     flush_sequence();
1855     SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
1856     ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
1857
1858     ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
1859     ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
1860
1861     /* restore original WS_VISIBLE state */
1862     SetWindowLongA(hwnd, GWL_STYLE, style);
1863
1864     flush_sequence();
1865 }
1866
1867 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1868 {
1869     struct message msg;
1870
1871     trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1872
1873     msg.message = message;
1874     msg.flags = sent|wparam|lparam;
1875     msg.wParam = wParam;
1876     msg.lParam = lParam;
1877     add_message(&msg);
1878
1879     if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
1880     if (message == WM_TIMER) EndDialog( hwnd, 0 );
1881     return 0;
1882 }
1883
1884 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
1885 {
1886     DWORD style, exstyle;
1887     INT xmin, xmax;
1888
1889     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
1890     style = GetWindowLongA(hwnd, GWL_STYLE);
1891     /* do not be confused by WS_DLGFRAME set */
1892     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
1893
1894     if (clear) ok(style & clear, "style %08lx should be set\n", clear);
1895     if (set) ok(!(style & set), "style %08lx should not be set\n", set);
1896
1897     ok(SetScrollRange(hwnd, ctl, min, max, FALSE), "SetScrollRange(%d) error %ld\n", ctl, GetLastError());
1898     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
1899         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
1900     else
1901         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", TRUE);
1902
1903     style = GetWindowLongA(hwnd, GWL_STYLE);
1904     if (set) ok(style & set, "style %08lx should be set\n", set);
1905     if (clear) ok(!(style & clear), "style %08lx should not be set\n", clear);
1906
1907     /* a subsequent call should do nothing */
1908     ok(SetScrollRange(hwnd, ctl, min, max, FALSE), "SetScrollRange(%d) error %ld\n", ctl, GetLastError());
1909     ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
1910
1911     xmin = 0xdeadbeef;
1912     xmax = 0xdeadbeef;
1913     trace("Ignore GetScrollRange error below if you are on Win9x\n");
1914     ok(GetScrollRange(hwnd, ctl, &xmin, &xmax), "GetScrollRange(%d) error %ld\n", ctl, GetLastError());
1915     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT)", FALSE);
1916     ok(xmin == min, "unexpected min scroll value %d\n", xmin);
1917     ok(xmax == max, "unexpected max scroll value %d\n", xmax);
1918 }
1919
1920 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
1921 {
1922     DWORD style, exstyle;
1923     SCROLLINFO si;
1924
1925     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
1926     style = GetWindowLongA(hwnd, GWL_STYLE);
1927     /* do not be confused by WS_DLGFRAME set */
1928     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
1929
1930     if (clear) ok(style & clear, "style %08lx should be set\n", clear);
1931     if (set) ok(!(style & set), "style %08lx should not be set\n", set);
1932
1933     si.cbSize = sizeof(si);
1934     si.fMask = SIF_RANGE;
1935     si.nMin = min;
1936     si.nMax = max;
1937     SetScrollInfo(hwnd, ctl, &si, TRUE);
1938     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
1939         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
1940     else
1941         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", TRUE);
1942
1943     style = GetWindowLongA(hwnd, GWL_STYLE);
1944     if (set) ok(style & set, "style %08lx should be set\n", set);
1945     if (clear) ok(!(style & clear), "style %08lx should not be set\n", clear);
1946
1947     /* a subsequent call should do nothing */
1948     SetScrollInfo(hwnd, ctl, &si, TRUE);
1949     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
1950
1951     si.fMask = SIF_PAGE;
1952     si.nPage = 5;
1953     SetScrollInfo(hwnd, ctl, &si, FALSE);
1954     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
1955
1956     si.fMask = SIF_POS;
1957     si.nPos = max - 1;
1958     SetScrollInfo(hwnd, ctl, &si, FALSE);
1959     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
1960
1961     si.fMask = SIF_RANGE;
1962     si.nMin = 0xdeadbeef;
1963     si.nMax = 0xdeadbeef;
1964     ok(GetScrollInfo(hwnd, ctl, &si), "GetScrollInfo error %ld\n", GetLastError());
1965     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT)", FALSE);
1966     ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
1967     ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
1968 }
1969
1970 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
1971 static void test_scroll_messages(HWND hwnd)
1972 {
1973     SCROLLINFO si;
1974     INT min, max;
1975
1976     min = 0xdeadbeef;
1977     max = 0xdeadbeef;
1978     ok(GetScrollRange(hwnd, SB_CTL, &min, &max), "GetScrollRange error %ld\n", GetLastError());
1979     if (sequence->message != WmGetScrollRangeSeq[0].message)
1980         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
1981     /* values of min and max are undefined */
1982     flush_sequence();
1983
1984     ok(SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE), "SetScrollRange error %ld\n", GetLastError());
1985     if (sequence->message != WmSetScrollRangeSeq[0].message)
1986         trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
1987     flush_sequence();
1988
1989     min = 0xdeadbeef;
1990     max = 0xdeadbeef;
1991     ok(GetScrollRange(hwnd, SB_CTL, &min, &max), "GetScrollRange error %ld\n", GetLastError());
1992     if (sequence->message != WmGetScrollRangeSeq[0].message)
1993         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
1994     /* values of min and max are undefined */
1995     flush_sequence();
1996
1997     si.cbSize = sizeof(si);
1998     si.fMask = SIF_RANGE;
1999     si.nMin = 20;
2000     si.nMax = 160;
2001     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
2002     if (sequence->message != WmSetScrollRangeSeq[0].message)
2003         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
2004     flush_sequence();
2005
2006     si.fMask = SIF_PAGE;
2007     si.nPage = 10;
2008     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
2009     if (sequence->message != WmSetScrollRangeSeq[0].message)
2010         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
2011     flush_sequence();
2012
2013     si.fMask = SIF_POS;
2014     si.nPos = 20;
2015     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
2016     if (sequence->message != WmSetScrollRangeSeq[0].message)
2017         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
2018     flush_sequence();
2019
2020     si.fMask = SIF_RANGE;
2021     si.nMin = 0xdeadbeef;
2022     si.nMax = 0xdeadbeef;
2023     ok(GetScrollInfo(hwnd, SB_CTL, &si), "GetScrollInfo error %ld\n", GetLastError());
2024     if (sequence->message != WmGetScrollInfoSeq[0].message)
2025         trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
2026     /* values of min and max are undefined */
2027     flush_sequence();
2028
2029     /* set WS_HSCROLL */
2030     test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
2031     /* clear WS_HSCROLL */
2032     test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
2033
2034     /* set WS_HSCROLL */
2035     test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
2036     /* clear WS_HSCROLL */
2037     test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
2038
2039     /* set WS_VSCROLL */
2040     test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
2041     /* clear WS_VSCROLL */
2042     test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
2043
2044     /* set WS_VSCROLL */
2045     test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
2046     /* clear WS_VSCROLL */
2047     test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
2048 }
2049
2050 /* test if we receive the right sequence of messages */
2051 static void test_messages(void)
2052 {
2053     HWND hwnd, hparent, hchild;
2054     HWND hchild2, hbutton;
2055     HMENU hmenu;
2056
2057     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
2058                            100, 100, 200, 200, 0, 0, 0, NULL);
2059     ok (hwnd != 0, "Failed to create overlapped window\n");
2060     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
2061
2062     /* test ShowWindow(SW_HIDE) on a newly created invisible window */
2063     ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
2064     ok_sequence(WmHideInvisibleOverlappedSeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
2065
2066     /* test WM_SETREDRAW on a not visible top level window */
2067     test_WM_SETREDRAW(hwnd);
2068
2069     SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
2070     ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
2071     ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
2072
2073     ok(GetActiveWindow() == hwnd, "window should be active\n");
2074     ok(GetFocus() == hwnd, "window should have input focus\n");
2075     ShowWindow(hwnd, SW_HIDE);
2076     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", TRUE);
2077     
2078     ShowWindow(hwnd, SW_SHOW);
2079     ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
2080
2081     ok(GetActiveWindow() == hwnd, "window should be active\n");
2082     ok(GetFocus() == hwnd, "window should have input focus\n");
2083     SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
2084     ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", TRUE);
2085     ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
2086
2087     /* test WM_SETREDRAW on a visible top level window */
2088     ShowWindow(hwnd, SW_SHOW);
2089     test_WM_SETREDRAW(hwnd);
2090
2091     trace("testing scroll APIs on a visible top level window %p\n", hwnd);
2092     test_scroll_messages(hwnd);
2093
2094     DestroyWindow(hwnd);
2095     ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
2096
2097     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
2098                               100, 100, 200, 200, 0, 0, 0, NULL);
2099     ok (hparent != 0, "Failed to create parent window\n");
2100     flush_sequence();
2101
2102     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
2103                              0, 0, 10, 10, hparent, 0, 0, NULL);
2104     ok (hchild != 0, "Failed to create child window\n");
2105     ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", TRUE);
2106     DestroyWindow(hchild);
2107     flush_sequence();
2108
2109     /* visible child window with a caption */
2110     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
2111                              WS_CHILD | WS_VISIBLE | WS_CAPTION,
2112                              0, 0, 10, 10, hparent, 0, 0, NULL);
2113     ok (hchild != 0, "Failed to create child window\n");
2114     ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
2115
2116     trace("testing scroll APIs on a visible child window %p\n", hchild);
2117     test_scroll_messages(hchild);
2118
2119     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
2120     ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
2121
2122     DestroyWindow(hchild);
2123     flush_sequence();
2124
2125     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
2126                              0, 0, 10, 10, hparent, 0, 0, NULL);
2127     ok (hchild != 0, "Failed to create child window\n");
2128     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
2129     
2130     hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
2131                                100, 100, 50, 50, hparent, 0, 0, NULL);
2132     ok (hchild2 != 0, "Failed to create child2 window\n");
2133     flush_sequence();
2134
2135     hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
2136                               0, 100, 50, 50, hchild, 0, 0, NULL);
2137     ok (hbutton != 0, "Failed to create button window\n");
2138
2139     /* test WM_SETREDRAW on a not visible child window */
2140     test_WM_SETREDRAW(hchild);
2141
2142     ShowWindow(hchild, SW_SHOW);
2143     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
2144
2145     ShowWindow(hchild, SW_HIDE);
2146     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
2147
2148     ShowWindow(hchild, SW_SHOW);
2149     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
2150
2151     /* test WM_SETREDRAW on a visible child window */
2152     test_WM_SETREDRAW(hchild);
2153
2154     MoveWindow(hchild, 10, 10, 20, 20, TRUE);
2155     ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
2156
2157     ShowWindow(hchild, SW_HIDE);
2158     flush_sequence();
2159     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
2160     ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
2161
2162     ShowWindow(hchild, SW_HIDE);
2163     flush_sequence();
2164     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
2165     ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
2166
2167     /* DestroyWindow sequence below expects that a child has focus */
2168     SetFocus(hchild);
2169     flush_sequence();
2170
2171     DestroyWindow(hchild);
2172     ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
2173     DestroyWindow(hchild2);
2174     DestroyWindow(hbutton);
2175
2176     flush_sequence();
2177     hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
2178                              0, 0, 100, 100, hparent, 0, 0, NULL);
2179     ok (hchild != 0, "Failed to create child popup window\n");
2180     ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
2181     DestroyWindow(hchild);
2182
2183     /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
2184     flush_sequence();
2185     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
2186                              0, 0, 100, 100, hparent, 0, 0, NULL);
2187     ok (hchild != 0, "Failed to create popup window\n");
2188     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
2189     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
2190     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
2191     flush_sequence();
2192     ShowWindow(hchild, SW_SHOW);
2193     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
2194     flush_sequence();
2195     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
2196     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
2197     flush_sequence();
2198     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
2199     ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
2200     DestroyWindow(hchild);
2201
2202     /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
2203      * changes nothing in message sequences.
2204      */
2205     flush_sequence();
2206     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
2207                              0, 0, 100, 100, hparent, 0, 0, NULL);
2208     ok (hchild != 0, "Failed to create popup window\n");
2209     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
2210     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
2211     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
2212     flush_sequence();
2213     ShowWindow(hchild, SW_SHOW);
2214     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
2215     flush_sequence();
2216     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
2217     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
2218     DestroyWindow(hchild);
2219
2220     flush_sequence();
2221     hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
2222                            0, 0, 100, 100, hparent, 0, 0, NULL);
2223     ok(hwnd != 0, "Failed to create custom dialog window\n");
2224     ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
2225
2226     trace("testing scroll APIs on a visible dialog %p\n", hwnd);
2227     test_scroll_messages(hwnd);
2228
2229     flush_sequence();
2230     after_end_dialog = 1;
2231     EndDialog( hwnd, 0 );
2232     ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
2233
2234     DestroyWindow(hwnd);
2235     after_end_dialog = 0;
2236
2237     flush_sequence();
2238     DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
2239     ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
2240
2241     /* test showing child with hidden parent */
2242     ShowWindow( hparent, SW_HIDE );
2243     flush_sequence();
2244
2245     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
2246                              0, 0, 10, 10, hparent, 0, 0, NULL);
2247     ok (hchild != 0, "Failed to create child window\n");
2248     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
2249
2250     ShowWindow( hchild, SW_SHOW );
2251     ok_sequence(WmShowChildInvisibleParentSeq, "ShowWindow:show child with invisible parent", TRUE);
2252     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
2253     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
2254
2255     ShowWindow( hchild, SW_HIDE );
2256     ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", TRUE);
2257     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
2258     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
2259
2260     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
2261     ok_sequence(WmShowChildInvisibleParentSeq_2, "SetWindowPos:show child with invisible parent", TRUE);
2262     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
2263     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
2264
2265     SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
2266     ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", TRUE);
2267     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
2268     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
2269
2270     DestroyWindow(hparent);
2271     flush_sequence();
2272
2273     /* Message sequence for SetMenu */
2274     hmenu = CreateMenu();
2275     ok (hmenu != 0, "Failed to create menu\n");
2276     ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
2277     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
2278                            100, 100, 200, 200, 0, hmenu, 0, NULL);
2279     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
2280     ok (SetMenu(hwnd, 0), "SetMenu\n");
2281     ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
2282     ok (SetMenu(hwnd, 0), "SetMenu\n");
2283     ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
2284     ShowWindow(hwnd, SW_SHOW);
2285     flush_sequence();
2286     ok (SetMenu(hwnd, 0), "SetMenu\n");
2287     ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", TRUE);
2288     ok (SetMenu(hwnd, hmenu), "SetMenu\n");
2289     ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", TRUE);
2290
2291     ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
2292     ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", TRUE);
2293
2294     DestroyWindow(hwnd);
2295     flush_sequence();
2296
2297     /* Message sequence for EnableWindow */
2298     hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
2299                               100, 100, 200, 200, 0, 0, 0, NULL);
2300     ok (hparent != 0, "Failed to create parent window\n");
2301     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
2302                              0, 0, 10, 10, hparent, 0, 0, NULL);
2303     ok (hchild != 0, "Failed to create child window\n");
2304
2305     SetFocus(hchild);
2306     flush_sequence();
2307
2308     EnableWindow(hparent, FALSE);
2309     ok_sequence(WmEnableWindowSeq, "EnableWindow", FALSE);
2310
2311     DestroyWindow(hparent);
2312     flush_sequence();
2313 }
2314
2315 /****************** button message test *************************/
2316 static const struct message WmSetFocusButtonSeq[] =
2317 {
2318     { HCBT_SETFOCUS, hook },
2319     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2320     { WM_SETFOCUS, sent|wparam, 0 },
2321     { WM_CTLCOLORBTN, sent|defwinproc },
2322     { 0 }
2323 };
2324 static const struct message WmKillFocusButtonSeq[] =
2325 {
2326     { HCBT_SETFOCUS, hook },
2327     { WM_KILLFOCUS, sent|wparam, 0 },
2328     { WM_CTLCOLORBTN, sent|defwinproc },
2329     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2330     { 0 }
2331 };
2332 static const struct message WmSetFocusStaticSeq[] =
2333 {
2334     { HCBT_SETFOCUS, hook },
2335     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2336     { WM_SETFOCUS, sent|wparam, 0 },
2337     { WM_CTLCOLORSTATIC, sent|defwinproc },
2338     { 0 }
2339 };
2340 static const struct message WmKillFocusStaticSeq[] =
2341 {
2342     { HCBT_SETFOCUS, hook },
2343     { WM_KILLFOCUS, sent|wparam, 0 },
2344     { WM_CTLCOLORSTATIC, sent|defwinproc },
2345     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2346     { 0 }
2347 };
2348 static const struct message WmLButtonDownSeq[] =
2349 {
2350     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
2351     { HCBT_SETFOCUS, hook },
2352     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2353     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
2354     { WM_CTLCOLORBTN, sent|defwinproc },
2355     { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
2356     { WM_CTLCOLORBTN, sent|defwinproc },
2357     { 0 }
2358 };
2359 static const struct message WmLButtonUpSeq[] =
2360 {
2361     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
2362     { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
2363     { WM_CTLCOLORBTN, sent|defwinproc },
2364     { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
2365     { 0 }
2366 };
2367
2368 static WNDPROC old_button_proc;
2369
2370 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2371 {
2372     static long defwndproc_counter = 0;
2373     LRESULT ret;
2374     struct message msg;
2375
2376     trace("button: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2377
2378     msg.message = message;
2379     msg.flags = sent|wparam|lparam;
2380     if (defwndproc_counter) msg.flags |= defwinproc;
2381     msg.wParam = wParam;
2382     msg.lParam = lParam;
2383     add_message(&msg);
2384
2385     if (message == BM_SETSTATE)
2386         ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
2387
2388     defwndproc_counter++;
2389     ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
2390     defwndproc_counter--;
2391
2392     return ret;
2393 }
2394
2395 static void subclass_button(void)
2396 {
2397     WNDCLASSA cls;
2398
2399     if (!GetClassInfoA(0, "button", &cls)) assert(0);
2400
2401     old_button_proc = cls.lpfnWndProc;
2402
2403     cls.hInstance = GetModuleHandle(0);
2404     cls.lpfnWndProc = button_hook_proc;
2405     cls.lpszClassName = "my_button_class";
2406     if (!RegisterClassA(&cls)) assert(0);
2407 }
2408
2409 static void test_button_messages(void)
2410 {
2411     static const struct
2412     {
2413         DWORD style;
2414         const struct message *setfocus;
2415         const struct message *killfocus;
2416     } button[] = {
2417         { BS_PUSHBUTTON, WmSetFocusButtonSeq, WmKillFocusButtonSeq },
2418         { BS_DEFPUSHBUTTON, WmSetFocusButtonSeq, WmKillFocusButtonSeq },
2419         { BS_CHECKBOX, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2420         { BS_AUTOCHECKBOX, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2421         { BS_RADIOBUTTON, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2422         { BS_3STATE, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2423         { BS_AUTO3STATE, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2424         { BS_GROUPBOX, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2425         { BS_USERBUTTON, WmSetFocusButtonSeq, WmKillFocusButtonSeq },
2426         { BS_AUTORADIOBUTTON, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2427         { BS_OWNERDRAW, WmSetFocusButtonSeq, WmKillFocusButtonSeq }
2428     };
2429     unsigned int i;
2430     HWND hwnd;
2431
2432     subclass_button();
2433
2434     for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
2435     {
2436         hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP,
2437                                0, 0, 50, 14, 0, 0, 0, NULL);
2438         ok(hwnd != 0, "Failed to create button window\n");
2439
2440         ShowWindow(hwnd, SW_SHOW);
2441         UpdateWindow(hwnd);
2442         SetFocus(0);
2443         flush_sequence();
2444
2445         trace("button style %08lx\n", button[i].style);
2446         SetFocus(hwnd);
2447         ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
2448
2449         SetFocus(0);
2450         ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
2451
2452         DestroyWindow(hwnd);
2453     }
2454
2455     hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP | WS_VISIBLE,
2456                            0, 0, 50, 14, 0, 0, 0, NULL);
2457     ok(hwnd != 0, "Failed to create button window\n");
2458
2459     SetFocus(0);
2460     flush_sequence();
2461
2462     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
2463     ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
2464
2465     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
2466     ok_sequence(WmLButtonUpSeq, "WM_LBUTTONDOWN on a button", FALSE);
2467     DestroyWindow(hwnd);
2468 }
2469
2470 /************* painting message test ********************/
2471
2472 static void dump_region(HRGN hrgn)
2473 {
2474     DWORD i, size;
2475     RGNDATA *data = NULL;
2476     RECT *rect;
2477
2478     if (!hrgn)
2479     {
2480         printf( "null region\n" );
2481         return;
2482     }
2483     if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
2484     if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
2485     GetRegionData( hrgn, size, data );
2486     printf("%ld rects:", data->rdh.nCount );
2487     for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
2488         printf( " (%ld,%ld)-(%ld,%ld)", rect->left, rect->top, rect->right, rect->bottom );
2489     printf("\n");
2490     HeapFree( GetProcessHeap(), 0, data );
2491 }
2492
2493 static void check_update_rgn( HWND hwnd, HRGN hrgn )
2494 {
2495     INT ret;
2496     RECT r1, r2;
2497     HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
2498     HRGN update = CreateRectRgn( 0, 0, 0, 0 );
2499
2500     ret = GetUpdateRgn( hwnd, update, FALSE );
2501     ok( ret != ERROR, "GetUpdateRgn failed\n" );
2502     if (ret == NULLREGION)
2503     {
2504         ok( !hrgn, "Update region shouldn't be empty\n" );
2505     }
2506     else
2507     {
2508         if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
2509         {
2510             ok( 0, "Regions are different\n" );
2511             if (winetest_debug > 0)
2512             {
2513                 printf( "Update region: " );
2514                 dump_region( update );
2515                 printf( "Wanted region: " );
2516                 dump_region( hrgn );
2517             }
2518         }
2519     }
2520     GetRgnBox( update, &r1 );
2521     GetUpdateRect( hwnd, &r2, FALSE );
2522     ok( r1.left == r2.left && r1.top == r2.top && r1.right == r2.right && r1.bottom == r2.bottom,
2523         "Rectangles are different: %ld,%ld-%ld,%ld / %ld,%ld-%ld,%ld\n",
2524         r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom );
2525
2526     DeleteObject( tmp );
2527     DeleteObject( update );
2528 }
2529
2530 static const struct message WmInvalidateRgn[] = {
2531     { WM_NCPAINT, sent },
2532     { WM_GETTEXT, sent|defwinproc|optional },
2533     { 0 }
2534 };
2535
2536 static const struct message WmInvalidateFull[] = {
2537     { WM_NCPAINT, sent|wparam, 1 },
2538     { WM_GETTEXT, sent|defwinproc|optional },
2539     { 0 }
2540 };
2541
2542 static const struct message WmInvalidateErase[] = {
2543     { WM_NCPAINT, sent|wparam, 1 },
2544     { WM_GETTEXT, sent|defwinproc|optional },
2545     { WM_ERASEBKGND, sent },
2546     { 0 }
2547 };
2548
2549 static const struct message WmInvalidatePaint[] = {
2550     { WM_PAINT, sent },
2551     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
2552     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
2553     { 0 }
2554 };
2555
2556 static const struct message WmInvalidateErasePaint[] = {
2557     { WM_PAINT, sent },
2558     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
2559     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
2560     { WM_ERASEBKGND, sent|beginpaint },
2561     { 0 }
2562 };
2563
2564 static const struct message WmErase[] = {
2565     { WM_ERASEBKGND, sent },
2566     { 0 }
2567 };
2568
2569 static const struct message WmPaint[] = {
2570     { WM_PAINT, sent },
2571     { 0 }
2572 };
2573
2574 static void test_paint_messages(void)
2575 {
2576     RECT rect;
2577     MSG msg;
2578     HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
2579     HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
2580     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
2581                                 100, 100, 200, 200, 0, 0, 0, NULL);
2582     ok (hwnd != 0, "Failed to create overlapped window\n");
2583
2584     ShowWindow( hwnd, SW_SHOW );
2585     UpdateWindow( hwnd );
2586     check_update_rgn( hwnd, 0 );
2587     SetRectRgn( hrgn, 10, 10, 20, 20 );
2588     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
2589     check_update_rgn( hwnd, hrgn );
2590     SetRectRgn( hrgn2, 20, 20, 30, 30 );
2591     RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
2592     CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
2593     check_update_rgn( hwnd, hrgn );
2594     /* validate everything */
2595     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
2596     check_update_rgn( hwnd, 0 );
2597     /* now with frame */
2598     SetRectRgn( hrgn, -5, -5, 20, 20 );
2599
2600     flush_sequence();
2601     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
2602     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
2603
2604     SetRectRgn( hrgn, 0, 0, 20, 20 );  /* GetUpdateRgn clips to client area */
2605     check_update_rgn( hwnd, hrgn );
2606
2607     flush_sequence();
2608     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
2609     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
2610
2611     flush_sequence();
2612     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
2613     ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
2614
2615     GetClientRect( hwnd, &rect );
2616     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
2617     check_update_rgn( hwnd, hrgn );
2618
2619     flush_sequence();
2620     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
2621     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
2622
2623     flush_sequence();
2624     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
2625     ok_sequence( WmInvalidatePaint, "InvalidatePaint", TRUE );
2626     check_update_rgn( hwnd, 0 );
2627
2628     flush_sequence();
2629     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
2630     ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
2631     check_update_rgn( hwnd, 0 );
2632
2633     flush_sequence();
2634     SetRectRgn( hrgn, 0, 0, 100, 100 );
2635     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
2636     SetRectRgn( hrgn, 0, 0, 50, 100 );
2637     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
2638     SetRectRgn( hrgn, 50, 0, 100, 100 );
2639     check_update_rgn( hwnd, hrgn );
2640     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
2641     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );  /* must not generate messages, everything is valid */
2642     check_update_rgn( hwnd, 0 );
2643
2644     flush_sequence();
2645     SetRectRgn( hrgn, 0, 0, 100, 100 );
2646     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
2647     SetRectRgn( hrgn, 0, 0, 100, 50 );
2648     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
2649     ok_sequence( WmErase, "Erase", FALSE );
2650     SetRectRgn( hrgn, 0, 50, 100, 100 );
2651     check_update_rgn( hwnd, hrgn );
2652
2653     flush_sequence();
2654     SetRectRgn( hrgn, 0, 0, 100, 100 );
2655     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
2656     SetRectRgn( hrgn, 0, 0, 50, 50 );
2657     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
2658     ok_sequence( WmPaint, "Paint", FALSE );
2659
2660     flush_sequence();
2661     SetRectRgn( hrgn, -4, -4, -2, -2 );
2662     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
2663     SetRectRgn( hrgn, -4, -4, -3, -3 );
2664     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
2665     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
2666
2667     flush_sequence();
2668     SetRectRgn( hrgn, -4, -4, -2, -2 );
2669     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
2670     SetRectRgn( hrgn, -4, -4, -3, -3 );
2671     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
2672     SetRectRgn( hrgn, 0, 0, 1, 1 );
2673     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
2674     ok_sequence( WmPaint, "Paint", TRUE );
2675
2676     flush_sequence();
2677     SetRectRgn( hrgn, -4, -4, -1, -1 );
2678     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
2679     RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
2680     /* make sure no WM_PAINT was generated */
2681     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
2682     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
2683
2684     flush_sequence();
2685     SetRectRgn( hrgn, -4, -4, -1, -1 );
2686     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
2687     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
2688     {
2689         if (msg.hwnd == hwnd && msg.message == WM_PAINT)
2690         {
2691             /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
2692             INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
2693             ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
2694             ret = GetUpdateRect( hwnd, &rect, FALSE );
2695             ok( ret, "Invalid GetUpdateRect result %d\n", ret );
2696             /* this will send WM_NCPAINT and validate the non client area */
2697             ret = GetUpdateRect( hwnd, &rect, TRUE );
2698             ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
2699         }
2700         else DispatchMessage( &msg );
2701     }
2702     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
2703
2704     DeleteObject( hrgn );
2705     DeleteObject( hrgn2 );
2706     DestroyWindow( hwnd );
2707 }
2708
2709 struct wnd_event
2710 {
2711     HWND hwnd;
2712     HANDLE event;
2713 };
2714
2715 static DWORD WINAPI thread_proc(void *param)
2716 {
2717     MSG msg;
2718     struct wnd_event *wnd_event = (struct wnd_event *)param;
2719
2720     wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
2721                                       100, 100, 200, 200, 0, 0, 0, NULL);
2722     ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
2723
2724     SetEvent(wnd_event->event);
2725
2726     while (GetMessage(&msg, 0, 0, 0))
2727     {
2728         TranslateMessage(&msg);
2729         DispatchMessage(&msg);
2730     }
2731
2732     return 0;
2733 }
2734
2735 static void test_interthread_messages(void)
2736 {
2737     HANDLE hThread;
2738     DWORD tid;
2739     WNDPROC proc;
2740     MSG msg;
2741     char buf[256];
2742     int len, expected_len;
2743     struct wnd_event wnd_event;
2744
2745     wnd_event.event = CreateEvent(NULL, 0, 0, NULL);
2746
2747     hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
2748     ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError());
2749
2750     ok(WaitForSingleObject(wnd_event.event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2751
2752     CloseHandle(wnd_event.event);
2753
2754     SetLastError(0xdeadbeef);
2755     ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeded\n");
2756     ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error code %ld\n", GetLastError());
2757
2758     proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
2759     ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %ld\n", GetLastError());
2760
2761     expected_len = lstrlenA("window caption text");
2762     memset(buf, 0, sizeof(buf));
2763     SetLastError(0xdeadbeef);
2764     len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
2765     ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %ld, len %d, expected len %d\n", GetLastError(), len, expected_len);
2766     ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
2767
2768     msg.hwnd = wnd_event.hwnd;
2769     msg.message = WM_GETTEXT;
2770     msg.wParam = sizeof(buf);
2771     msg.lParam = (LPARAM)buf;
2772     memset(buf, 0, sizeof(buf));
2773     SetLastError(0xdeadbeef);
2774     len = DispatchMessageA(&msg);
2775     ok(!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
2776        "DispatchMessageA(WM_GETTEXT) succeded on another thread window: ret %d, error %ld\n", len, GetLastError());
2777
2778     msg.hwnd = wnd_event.hwnd;
2779     msg.message = WM_TIMER;
2780     msg.wParam = 0;
2781     msg.lParam = GetWindowLongW(wnd_event.hwnd,GWL_WNDPROC);
2782     SetLastError(0xdeadbeef);
2783     len = DispatchMessageA(&msg);
2784     ok(!len && GetLastError() == 0xdeadbeef,
2785        "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %ld\n", len, GetLastError());
2786
2787     ok(PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0), "PostMessageA(WM_QUIT) error %ld\n", GetLastError());
2788
2789     ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2790     CloseHandle(hThread);
2791 }
2792
2793 /************* window procedures ********************/
2794
2795 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2796 {
2797     static long defwndproc_counter = 0;
2798     static long beginpaint_counter = 0;
2799     LRESULT ret;
2800     struct message msg;
2801
2802     trace("%p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2803
2804     switch (message)
2805     {
2806         case WM_WINDOWPOSCHANGING:
2807         case WM_WINDOWPOSCHANGED:
2808         {
2809             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
2810
2811             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
2812             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
2813                   winpos->hwnd, winpos->hwndInsertAfter,
2814                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
2815
2816             /* Log only documented flags, win2k uses 0x1000 and 0x2000
2817              * in the high word for internal purposes
2818              */
2819             wParam = winpos->flags & 0xffff;
2820             break;
2821         }
2822     }
2823
2824     msg.message = message;
2825     msg.flags = sent|wparam|lparam;
2826     if (defwndproc_counter) msg.flags |= defwinproc;
2827     if (beginpaint_counter) msg.flags |= beginpaint;
2828     msg.wParam = wParam;
2829     msg.lParam = lParam;
2830     add_message(&msg);
2831
2832     if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
2833     {
2834         HWND parent = GetParent(hwnd);
2835         RECT rc;
2836         MINMAXINFO *minmax = (MINMAXINFO *)lParam;
2837
2838         GetClientRect(parent, &rc);
2839         trace("parent %p client size = (%ld x %ld)\n", parent, rc.right, rc.bottom);
2840
2841         trace("ptReserved = (%ld,%ld)\n"
2842               "ptMaxSize = (%ld,%ld)\n"
2843               "ptMaxPosition = (%ld,%ld)\n"
2844               "ptMinTrackSize = (%ld,%ld)\n"
2845               "ptMaxTrackSize = (%ld,%ld)\n",
2846               minmax->ptReserved.x, minmax->ptReserved.y,
2847               minmax->ptMaxSize.x, minmax->ptMaxSize.y,
2848               minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
2849               minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
2850               minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
2851
2852         ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %ld != %ld\n",
2853            minmax->ptMaxSize.x, rc.right);
2854         ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %ld != %ld\n",
2855            minmax->ptMaxSize.y, rc.bottom);
2856     }
2857
2858     if (message == WM_PAINT)
2859     {
2860         PAINTSTRUCT ps;
2861         beginpaint_counter++;
2862         BeginPaint( hwnd, &ps );
2863         beginpaint_counter--;
2864         EndPaint( hwnd, &ps );
2865         return 0;
2866     }
2867
2868     defwndproc_counter++;
2869     ret = DefWindowProcA(hwnd, message, wParam, lParam);
2870     defwndproc_counter--;
2871
2872     return ret;
2873 }
2874
2875 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2876 {
2877     static long defwndproc_counter = 0;
2878     LRESULT ret;
2879     struct message msg;
2880
2881     trace("popup: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2882
2883     msg.message = message;
2884     msg.flags = sent|wparam|lparam;
2885     if (defwndproc_counter) msg.flags |= defwinproc;
2886     msg.wParam = wParam;
2887     msg.lParam = lParam;
2888     add_message(&msg);
2889
2890     if (message == WM_CREATE)
2891     {
2892         DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
2893         SetWindowLongA(hwnd, GWL_STYLE, style);
2894     }
2895
2896     defwndproc_counter++;
2897     ret = DefWindowProcA(hwnd, message, wParam, lParam);
2898     defwndproc_counter--;
2899
2900     return ret;
2901 }
2902
2903 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2904 {
2905     static long defwndproc_counter = 0;
2906     LRESULT ret;
2907     struct message msg;
2908
2909     trace("parent: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2910
2911     if (message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
2912         message == WM_SETFOCUS || message == WM_KILLFOCUS ||
2913         message == WM_ENABLE || message == WM_ENTERIDLE ||
2914         message == WM_IME_SETCONTEXT)
2915     {
2916         msg.message = message;
2917         msg.flags = sent|parent|wparam|lparam;
2918         if (defwndproc_counter) msg.flags |= defwinproc;
2919         msg.wParam = wParam;
2920         msg.lParam = lParam;
2921         add_message(&msg);
2922     }
2923
2924     defwndproc_counter++;
2925     ret = DefWindowProcA(hwnd, message, wParam, lParam);
2926     defwndproc_counter--;
2927
2928     return ret;
2929 }
2930
2931 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2932 {
2933     static long defwndproc_counter = 0;
2934     LRESULT ret;
2935     struct message msg;
2936
2937     trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2938
2939     DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
2940     ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
2941     if (after_end_dialog)
2942         ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
2943     else
2944         ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
2945
2946     msg.message = message;
2947     msg.flags = sent|wparam|lparam;
2948     if (defwndproc_counter) msg.flags |= defwinproc;
2949     msg.wParam = wParam;
2950     msg.lParam = lParam;
2951     add_message(&msg);
2952
2953     defwndproc_counter++;
2954     ret = DefDlgProcA(hwnd, message, wParam, lParam);
2955     defwndproc_counter--;
2956
2957     return ret;
2958 }
2959
2960 static BOOL RegisterWindowClasses(void)
2961 {
2962     WNDCLASSA cls;
2963
2964     cls.style = 0;
2965     cls.lpfnWndProc = MsgCheckProcA;
2966     cls.cbClsExtra = 0;
2967     cls.cbWndExtra = 0;
2968     cls.hInstance = GetModuleHandleA(0);
2969     cls.hIcon = 0;
2970     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
2971     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
2972     cls.lpszMenuName = NULL;
2973     cls.lpszClassName = "TestWindowClass";
2974     if(!RegisterClassA(&cls)) return FALSE;
2975
2976     cls.lpfnWndProc = PopupMsgCheckProcA;
2977     cls.lpszClassName = "TestPopupClass";
2978     if(!RegisterClassA(&cls)) return FALSE;
2979
2980     cls.lpfnWndProc = ParentMsgCheckProcA;
2981     cls.lpszClassName = "TestParentClass";
2982     if(!RegisterClassA(&cls)) return FALSE;
2983
2984     cls.lpfnWndProc = DefWindowProcA;
2985     cls.lpszClassName = "SimpleWindowClass";
2986     if(!RegisterClassA(&cls)) return FALSE;
2987
2988     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
2989     cls.lpfnWndProc = TestDlgProcA;
2990     cls.lpszClassName = "TestDialogClass";
2991     if(!RegisterClassA(&cls)) return FALSE;
2992
2993     return TRUE;
2994 }
2995
2996 static HHOOK hCBT_hook;
2997
2998 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
2999
3000     char buf[256];
3001
3002     trace("CBT: %d, %08x, %08lx\n", nCode, wParam, lParam);
3003
3004     if (nCode == HCBT_SYSCOMMAND)
3005     {
3006         struct message msg;
3007
3008         msg.message = nCode;
3009         msg.flags = hook;
3010         msg.wParam = wParam;
3011         msg.lParam = lParam;
3012         add_message(&msg);
3013
3014         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
3015     }
3016
3017     /* Log also SetFocus(0) calls */
3018     if (!wParam) wParam = lParam;
3019
3020     if (GetClassNameA((HWND)wParam, buf, sizeof(buf)))
3021     {
3022         if (!strcmp(buf, "TestWindowClass") ||
3023             !strcmp(buf, "TestParentClass") ||
3024             !strcmp(buf, "TestPopupClass") ||
3025             !strcmp(buf, "SimpleWindowClass") ||
3026             !strcmp(buf, "TestDialogClass") ||
3027             !strcmp(buf, "MDI_frame_class") ||
3028             !strcmp(buf, "MDI_client_class") ||
3029             !strcmp(buf, "MDI_child_class") ||
3030             !strcmp(buf, "my_button_class") ||
3031             !strcmp(buf, "#32770"))
3032         {
3033             struct message msg;
3034
3035             msg.message = nCode;
3036             msg.flags = hook;
3037             msg.wParam = wParam;
3038             msg.lParam = lParam;
3039             add_message(&msg);
3040         }
3041     }
3042     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
3043 }
3044
3045 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
3046 static const WCHAR wszAnsi[] = {'U',0};
3047
3048 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
3049 {
3050     switch (uMsg)
3051     {
3052     case CB_FINDSTRINGEXACT:
3053         trace("String: %p\n", (LPCWSTR)lParam);
3054         if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
3055             return 1;
3056         if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
3057             return 0;
3058         return -1;
3059     }
3060     return DefWindowProcW(hwnd, uMsg, wParam, lParam);
3061 }
3062
3063 static void test_message_conversion(void)
3064 {
3065     static const WCHAR wszMsgConversionClass[] =
3066         {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
3067     WNDCLASSW cls;
3068     LRESULT lRes;
3069     HWND hwnd;
3070     WNDPROC wndproc;
3071
3072     cls.style = 0;
3073     cls.lpfnWndProc = MsgConversionProcW;
3074     cls.cbClsExtra = 0;
3075     cls.cbWndExtra = 0;
3076     cls.hInstance = GetModuleHandleW(NULL);
3077     cls.hIcon = NULL;
3078     cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
3079     cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
3080     cls.lpszMenuName = NULL;
3081     cls.lpszClassName = wszMsgConversionClass;
3082     /* this call will fail on Win9x, but that doesn't matter as this test is
3083      * meaningless on those platforms */
3084     if(!RegisterClassW(&cls)) return;
3085
3086     hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
3087                            100, 100, 200, 200, 0, 0, 0, NULL);
3088     ok(hwnd != NULL, "Window creation failed\n");
3089
3090     /* {W, A} -> A */
3091
3092     wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
3093     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3094     ok(lRes == 0, "String should have been converted\n");
3095     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3096     ok(lRes == 1, "String shouldn't have been converted\n");
3097
3098     /* {W, A} -> W */
3099
3100     wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
3101     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3102     ok(lRes == 1, "String shouldn't have been converted\n");
3103     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3104     ok(lRes == 1, "String shouldn't have been converted\n");
3105
3106     /* Synchronous messages */
3107
3108     lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3109     ok(lRes == 0, "String should have been converted\n");
3110     lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3111     ok(lRes == 1, "String shouldn't have been converted\n");
3112
3113     /* Asynchronous messages */
3114
3115     SetLastError(0);
3116     lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3117     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3118         "PostMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3119     SetLastError(0);
3120     lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3121     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3122         "PostMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3123     SetLastError(0);
3124     lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3125     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3126         "PosThreadtMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3127     SetLastError(0);
3128     lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3129     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3130         "PosThreadtMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3131     SetLastError(0);
3132     lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3133     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3134         "SendNotifyMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3135     SetLastError(0);
3136     lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3137     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3138         "SendNotifyMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3139     SetLastError(0);
3140     lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
3141     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3142         "SendMessageCallback on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3143     SetLastError(0);
3144     lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
3145     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3146         "SendMessageCallback on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
3147 }
3148
3149 START_TEST(msg)
3150 {
3151     if (!RegisterWindowClasses()) assert(0);
3152
3153     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
3154     assert(hCBT_hook);
3155
3156     test_messages();
3157     test_mdi_messages();
3158     test_button_messages();
3159     test_paint_messages();
3160     test_interthread_messages();
3161     test_message_conversion();
3162
3163     UnhookWindowsHookEx(hCBT_hook);
3164 }