Do not check for non NULL pointer before HeapFree'ing it. It's
[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 static int log_all_parent_messages;
773
774 static void add_message(const struct message *msg)
775 {
776     if (!sequence) 
777     {
778         sequence_size = 10;
779         sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof (struct message) );
780     }
781     if (sequence_cnt == sequence_size) 
782     {
783         sequence_size *= 2;
784         sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof (struct message) );
785     }
786     assert(sequence);
787
788     sequence[sequence_cnt].message = msg->message;
789     sequence[sequence_cnt].flags = msg->flags;
790     sequence[sequence_cnt].wParam = msg->wParam;
791     sequence[sequence_cnt].lParam = msg->lParam;
792
793     sequence_cnt++;
794 }
795
796 static void flush_sequence()
797 {
798     HeapFree(GetProcessHeap(), 0, sequence);
799     sequence = 0;
800     sequence_cnt = sequence_size = 0;
801 }
802
803 #define ok_sequence( exp, contx, todo) \
804         ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
805
806
807 static void ok_sequence_(const struct message *expected, const char *context, int todo,
808         const char *file, int line)
809 {
810     static const struct message end_of_sequence = { 0, 0, 0, 0 };
811     const struct message *actual;
812     int failcount = 0;
813     
814     add_message(&end_of_sequence);
815
816     actual = sequence;
817
818     while (expected->message && actual->message)
819     {
820         trace_( file, line)("expected %04x - actual %04x\n", expected->message, actual->message);
821
822         if (expected->message == actual->message)
823         {
824             if (expected->flags & wparam)
825             {
826                 if (expected->wParam != actual->wParam && todo)
827                 {
828                     todo_wine {
829                         failcount ++;
830                         ok_( file, line) (FALSE,
831                             "%s: in msg 0x%04x expecting wParam 0x%x got 0x%x\n",
832                             context, expected->message, expected->wParam, actual->wParam);
833                     }
834                 }
835                 else
836                 ok_( file, line) (expected->wParam == actual->wParam,
837                      "%s: in msg 0x%04x expecting wParam 0x%x got 0x%x\n",
838                      context, expected->message, expected->wParam, actual->wParam);
839             }
840             if (expected->flags & lparam)
841                  ok_( file, line) (expected->lParam == actual->lParam,
842                      "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
843                      context, expected->message, expected->lParam, actual->lParam);
844             ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
845                 "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
846                 context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
847             ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
848                 "%s: the msg 0x%04x should %shave been sent by BeginPaint\n",
849                 context, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
850             ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
851                 "%s: the msg 0x%04x should have been %s\n",
852                 context, expected->message, (expected->flags & posted) ? "posted" : "sent");
853             ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
854                 "%s: the msg 0x%04x was expected in %s\n",
855                 context, expected->message, (expected->flags & parent) ? "parent" : "child");
856             ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
857                 "%s: the msg 0x%04x should have been sent by a hook\n",
858                 context, expected->message);
859             expected++;
860             actual++;
861         }
862         else if (expected->flags & optional)
863             expected++;
864         else if (todo)
865         {
866             failcount++;
867             todo_wine {
868                 ok_( file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
869                     context, expected->message, actual->message);
870             }
871             flush_sequence();
872             return;
873         }
874         else
875         {
876             ok_( file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
877                 context, expected->message, actual->message);
878             expected++;
879             actual++;
880         }
881     }
882
883     /* skip all optional trailing messages */
884     while (expected->message && (expected->flags & optional))
885         expected++;
886
887     if (todo)
888     {
889         todo_wine {
890             if (expected->message || actual->message) {
891                 failcount++;
892                 ok_( file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
893                     context, expected->message, actual->message);
894             }
895         }
896     }
897     else
898     {
899         if (expected->message || actual->message)
900             ok_( file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
901                 context, expected->message, actual->message);
902     }
903     if( todo && !failcount) /* succeeded yet marked todo */
904         todo_wine {
905             ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
906         }
907
908     flush_sequence();
909 }
910
911 /******************************** MDI test **********************************/
912
913 /* CreateWindow for MDI frame window, initially visible */
914 static const struct message WmCreateMDIframeSeq[] = {
915     { HCBT_CREATEWND, hook },
916     { WM_GETMINMAXINFO, sent },
917     { WM_NCCREATE, sent },
918     { WM_NCCALCSIZE, sent|wparam, 0 },
919     { WM_CREATE, sent },
920     { WM_SHOWWINDOW, sent|wparam, 1 },
921     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
922     { HCBT_ACTIVATE, hook },
923     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
924     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
925     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* Win9x */
926     { WM_ACTIVATEAPP, sent|wparam, 1 },
927     { WM_NCACTIVATE, sent|wparam, 1 },
928     { WM_ACTIVATE, sent|wparam, 1 },
929     { HCBT_SETFOCUS, hook },
930     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
931     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
932     /* Win9x adds SWP_NOZORDER below */
933     { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
934     { WM_SIZE, sent },
935     { WM_MOVE, sent },
936     { 0 }
937 };
938 /* DestroyWindow for MDI frame window, initially visible */
939 static const struct message WmDestroyMDIframeSeq[] = {
940     { HCBT_DESTROYWND, hook },
941     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
942     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
943     { WM_NCACTIVATE, sent|wparam, 0 },
944     { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
945     { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
946     { WM_DESTROY, sent },
947     { WM_NCDESTROY, sent },
948     { 0 }
949 };
950 /* CreateWindow for MDI client window, initially visible */
951 static const struct message WmCreateMDIclientSeq[] = {
952     { HCBT_CREATEWND, hook },
953     { WM_NCCREATE, sent },
954     { WM_NCCALCSIZE, sent|wparam, 0 },
955     { WM_CREATE, sent },
956     { WM_SIZE, sent },
957     { WM_MOVE, sent },
958     { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
959     { WM_SHOWWINDOW, sent|wparam, 1 },
960     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE|SWP_NOMOVE },
961     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
962     { 0 }
963 };
964 /* DestroyWindow for MDI client window, initially visible */
965 static const struct message WmDestroyMDIclientSeq[] = {
966     { HCBT_DESTROYWND, hook },
967     { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
968     { WM_SHOWWINDOW, sent|wparam, 0 },
969     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
970     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
971     { WM_DESTROY, sent },
972     { WM_NCDESTROY, sent },
973     { 0 }
974 };
975 /* CreateWindow for MDI child window, initially visible */
976 static const struct message WmCreateMDIchildVisibleSeq[] = {
977     { HCBT_CREATEWND, hook },
978     { WM_NCCREATE, sent }, 
979     { WM_NCCALCSIZE, sent|wparam, 0 },
980     { WM_CREATE, sent },
981     { WM_SIZE, sent },
982     { WM_MOVE, sent },
983     /* Win2k sends wparam set to
984      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
985      * while Win9x doesn't bother to set child window id according to
986      * CLIENTCREATESTRUCT.idFirstChild
987      */
988     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
989     { WM_SHOWWINDOW, sent|wparam, 1 },
990     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
991     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
992     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
993     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
994     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
995     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
996
997     /* Win9x: message sequence terminates here. */
998
999     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1000     { HCBT_SETFOCUS, hook }, /* in MDI client */
1001     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1002     { WM_SETFOCUS, sent }, /* in MDI client */
1003     { HCBT_SETFOCUS, hook },
1004     { WM_KILLFOCUS, sent }, /* in MDI client */
1005     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1006     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1007     { WM_SETFOCUS, sent|defwinproc },
1008     { WM_MDIACTIVATE, sent|defwinproc },
1009     { 0 }
1010 };
1011 /* DestroyWindow for MDI child window, initially visible */
1012 static const struct message WmDestroyMDIchildVisibleSeq[] = {
1013     { HCBT_DESTROYWND, hook },
1014     /* Win2k sends wparam set to
1015      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1016      * while Win9x doesn't bother to set child window id according to
1017      * CLIENTCREATESTRUCT.idFirstChild
1018      */
1019     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1020     { WM_SHOWWINDOW, sent|wparam, 0 },
1021     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1022     { WM_ERASEBKGND, sent|parent|optional },
1023     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1024
1025     /* { WM_DESTROY, sent }
1026      * Win9x: message sequence terminates here.
1027      */
1028
1029     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1030     { WM_KILLFOCUS, sent },
1031     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1032     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1033     { WM_SETFOCUS, sent }, /* in MDI client */
1034
1035     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1036     { WM_KILLFOCUS, sent }, /* in MDI client */
1037     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1038     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1039     { WM_SETFOCUS, sent }, /* in MDI client */
1040
1041     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1042     { WM_KILLFOCUS, sent },
1043     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1044     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1045     { WM_SETFOCUS, sent }, /* in MDI client */
1046
1047     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1048     { WM_KILLFOCUS, sent }, /* in MDI client */
1049     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1050     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1051     { WM_SETFOCUS, sent }, /* in MDI client */
1052
1053     { WM_DESTROY, sent },
1054
1055     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1056     { WM_KILLFOCUS, sent },
1057     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1058     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1059     { WM_SETFOCUS, sent }, /* in MDI client */
1060
1061     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1062     { WM_KILLFOCUS, sent }, /* in MDI client */
1063     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1064     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1065     { WM_SETFOCUS, sent }, /* in MDI client */
1066
1067     { WM_NCDESTROY, sent },
1068     { 0 }
1069 };
1070 /* CreateWindow for MDI child window, initially invisible */
1071 static const struct message WmCreateMDIchildInvisibleSeq[] = {
1072     { HCBT_CREATEWND, hook },
1073     { WM_NCCREATE, sent }, 
1074     { WM_NCCALCSIZE, sent|wparam, 0 },
1075     { WM_CREATE, sent },
1076     { WM_SIZE, sent },
1077     { WM_MOVE, sent },
1078     /* Win2k sends wparam set to
1079      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1080      * while Win9x doesn't bother to set child window id according to
1081      * CLIENTCREATESTRUCT.idFirstChild
1082      */
1083     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1084     { 0 }
1085 };
1086 /* DestroyWindow for MDI child window, initially invisible */
1087 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
1088     { HCBT_DESTROYWND, hook },
1089     /* Win2k sends wparam set to
1090      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1091      * while Win9x doesn't bother to set child window id according to
1092      * CLIENTCREATESTRUCT.idFirstChild
1093      */
1094     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1095     { WM_DESTROY, sent },
1096     { WM_NCDESTROY, sent },
1097     { 0 }
1098 };
1099 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
1100 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
1101     { HCBT_CREATEWND, hook },
1102     { WM_NCCREATE, sent }, 
1103     { WM_NCCALCSIZE, sent|wparam, 0 },
1104     { WM_CREATE, sent },
1105     { WM_SIZE, sent },
1106     { WM_MOVE, sent },
1107     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1108     { WM_GETMINMAXINFO, sent },
1109     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
1110     { WM_NCCALCSIZE, sent|wparam, 1 },
1111     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1112     { WM_SIZE, sent|defwinproc },
1113      /* in MDI frame */
1114     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1115     { WM_NCCALCSIZE, sent|wparam, 1 },
1116     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1117     /* Win2k sends wparam set to
1118      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1119      * while Win9x doesn't bother to set child window id according to
1120      * CLIENTCREATESTRUCT.idFirstChild
1121      */
1122     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1123     { WM_SHOWWINDOW, sent|wparam, 1 },
1124     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1125     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1126     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1127     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1128     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1129     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1130
1131     /* Win9x: message sequence terminates here. */
1132
1133     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1134     { HCBT_SETFOCUS, hook }, /* in MDI client */
1135     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1136     { WM_SETFOCUS, sent }, /* in MDI client */
1137     { HCBT_SETFOCUS, hook },
1138     { WM_KILLFOCUS, sent }, /* in MDI client */
1139     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1140     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1141     { WM_SETFOCUS, sent|defwinproc },
1142     { WM_MDIACTIVATE, sent|defwinproc },
1143      /* in MDI frame */
1144     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1145     { WM_NCCALCSIZE, sent|wparam, 1 },
1146     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1147     { 0 }
1148 };
1149 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
1150 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
1151     /* restore the 1st MDI child */
1152     { WM_SETREDRAW, sent|wparam, 0 },
1153     { HCBT_MINMAX, hook },
1154     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
1155     { WM_NCCALCSIZE, sent|wparam, 1 },
1156     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1157     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1158     { WM_SIZE, sent|defwinproc },
1159      /* in MDI frame */
1160     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1161     { WM_NCCALCSIZE, sent|wparam, 1 },
1162     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1163     { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
1164     /* create the 2nd MDI child */
1165     { HCBT_CREATEWND, hook },
1166     { WM_NCCREATE, sent }, 
1167     { WM_NCCALCSIZE, sent|wparam, 0 },
1168     { WM_CREATE, sent },
1169     { WM_SIZE, sent },
1170     { WM_MOVE, sent },
1171     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1172     { WM_GETMINMAXINFO, sent },
1173     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
1174     { WM_NCCALCSIZE, sent|wparam, 1 },
1175     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1176     { WM_SIZE, sent|defwinproc },
1177      /* in MDI frame */
1178     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1179     { WM_NCCALCSIZE, sent|wparam, 1 },
1180     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1181     /* Win2k sends wparam set to
1182      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1183      * while Win9x doesn't bother to set child window id according to
1184      * CLIENTCREATESTRUCT.idFirstChild
1185      */
1186     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1187     { WM_SHOWWINDOW, sent|wparam, 1 },
1188     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1189     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1190     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1191     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1192     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1193
1194     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
1195     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
1196
1197     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1198
1199     /* Win9x: message sequence terminates here. */
1200
1201     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1202     { HCBT_SETFOCUS, hook },
1203     { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
1204     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
1205     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1206     { WM_SETFOCUS, sent }, /* in MDI client */
1207     { HCBT_SETFOCUS, hook },
1208     { WM_KILLFOCUS, sent }, /* in MDI client */
1209     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1210     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1211     { WM_SETFOCUS, sent|defwinproc },
1212
1213     { WM_MDIACTIVATE, sent|defwinproc },
1214      /* in MDI frame */
1215     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1216     { WM_NCCALCSIZE, sent|wparam, 1 },
1217     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1218     { 0 }
1219 };
1220 /* WM_MDICREATE MDI child window, initially visible and maximized */
1221 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
1222     { WM_MDICREATE, sent },
1223     { HCBT_CREATEWND, hook },
1224     { WM_NCCREATE, sent }, 
1225     { WM_NCCALCSIZE, sent|wparam, 0 },
1226     { WM_CREATE, sent },
1227     { WM_SIZE, sent },
1228     { WM_MOVE, sent },
1229     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1230     { WM_GETMINMAXINFO, sent },
1231     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
1232     { WM_NCCALCSIZE, sent|wparam, 1 },
1233     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1234     { WM_SIZE, sent|defwinproc },
1235      /* in MDI frame */
1236     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1237     { WM_NCCALCSIZE, sent|wparam, 1 },
1238     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1239     /* Win2k sends wparam set to
1240      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1241      * while Win9x doesn't bother to set child window id according to
1242      * CLIENTCREATESTRUCT.idFirstChild
1243      */
1244     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1245     { WM_SHOWWINDOW, sent|wparam, 1 },
1246     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1247     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1248     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1249     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1250     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1251     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1252
1253     /* Win9x: message sequence terminates here. */
1254
1255     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1256     { HCBT_SETFOCUS, hook }, /* in MDI client */
1257     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1258     { WM_SETFOCUS, sent }, /* in MDI client */
1259     { HCBT_SETFOCUS, hook },
1260     { WM_KILLFOCUS, sent }, /* in MDI client */
1261     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1262     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1263     { WM_SETFOCUS, sent|defwinproc },
1264
1265     { WM_MDIACTIVATE, sent|defwinproc },
1266
1267      /* in MDI child */
1268     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1269     { WM_NCCALCSIZE, sent|wparam, 1 },
1270     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1271
1272      /* in MDI frame */
1273     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1274     { WM_NCCALCSIZE, sent|wparam, 1 },
1275     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1276     { WM_MOVE, sent|defwinproc },
1277     { WM_SIZE, sent|defwinproc },
1278
1279      /* in MDI client */
1280     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
1281     { WM_NCCALCSIZE, sent|wparam, 1 },
1282     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
1283     { WM_SIZE, sent },
1284
1285      /* in MDI child */
1286     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
1287     { WM_NCCALCSIZE, sent|wparam, 1 },
1288     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
1289     { WM_SIZE, sent|defwinproc },
1290
1291     { 0 }
1292 };
1293 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
1294 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
1295     { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
1296     { HCBT_SYSCOMMAND, hook },
1297     { WM_CLOSE, sent|defwinproc },
1298     { WM_MDIDESTROY, sent }, /* in MDI client */
1299
1300     /* bring the 1st MDI child to top */
1301     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
1302     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
1303     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
1304     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
1305     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
1306
1307     /* maximize the 1st MDI child */
1308     { HCBT_MINMAX, hook },
1309     { WM_GETMINMAXINFO, sent|defwinproc },
1310     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|0x8000 },
1311     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
1312     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
1313     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1314     { WM_SIZE, sent|defwinproc },
1315
1316     /* restore the 2nd MDI child */
1317     { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
1318     { HCBT_MINMAX, hook },
1319     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOZORDER|0x8000 },
1320     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
1321     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1322     { WM_SIZE, sent|defwinproc },
1323     { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
1324      /* in MDI frame */
1325     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1326     { WM_NCCALCSIZE, sent|wparam, 1 },
1327     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1328
1329     /* bring the 1st MDI child to top */
1330     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1331     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1332     { HCBT_SETFOCUS, hook },
1333     { WM_KILLFOCUS, sent|defwinproc },
1334     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
1335     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1336     { WM_SETFOCUS, sent }, /* in MDI client */
1337     { HCBT_SETFOCUS, hook },
1338     { WM_KILLFOCUS, sent }, /* in MDI client */
1339     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1340     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1341     { WM_SETFOCUS, sent|defwinproc },
1342     { WM_MDIACTIVATE, sent|defwinproc },
1343     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1344
1345     /* apparently ShowWindow(SW_SHOW) on an MDI client */
1346     { WM_SHOWWINDOW, sent|wparam, 1 },
1347     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1348     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1349     { WM_MDIREFRESHMENU, sent },
1350
1351     { HCBT_DESTROYWND, hook },
1352     /* Win2k sends wparam set to
1353      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1354      * while Win9x doesn't bother to set child window id according to
1355      * CLIENTCREATESTRUCT.idFirstChild
1356      */
1357     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1358     { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
1359     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1360     { WM_ERASEBKGND, sent|parent|optional },
1361     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1362
1363     { WM_DESTROY, sent|defwinproc },
1364     { WM_NCDESTROY, sent|defwinproc },
1365     { 0 }
1366 };
1367 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
1368 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
1369     { WM_MDIDESTROY, sent }, /* in MDI client */
1370     { WM_SHOWWINDOW, sent|wparam, 0 },
1371     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1372     { WM_ERASEBKGND, sent|parent|optional },
1373     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1374
1375     { HCBT_SETFOCUS, hook },
1376     { WM_KILLFOCUS, sent },
1377     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1378     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1379     { WM_SETFOCUS, sent }, /* in MDI client */
1380     { HCBT_SETFOCUS, hook },
1381     { WM_KILLFOCUS, sent }, /* in MDI client */
1382     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1383     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1384     { WM_SETFOCUS, sent },
1385
1386      /* in MDI child */
1387     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1388     { WM_NCCALCSIZE, sent|wparam, 1 },
1389     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1390
1391      /* in MDI frame */
1392     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1393     { WM_NCCALCSIZE, sent|wparam, 1 },
1394     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1395     { WM_MOVE, sent|defwinproc },
1396     { WM_SIZE, sent|defwinproc },
1397
1398      /* in MDI client */
1399     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
1400     { WM_NCCALCSIZE, sent|wparam, 1 },
1401     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
1402     { WM_SIZE, sent },
1403
1404      /* in MDI child */
1405     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
1406     { WM_NCCALCSIZE, sent|wparam, 1 },
1407     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
1408     { WM_SIZE, sent|defwinproc },
1409
1410      /* in MDI child */
1411     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1412     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
1413     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1414
1415      /* in MDI frame */
1416     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1417     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
1418     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1419     { WM_MOVE, sent|defwinproc },
1420     { WM_SIZE, sent|defwinproc },
1421
1422      /* in MDI client */
1423     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
1424     { WM_NCCALCSIZE, sent|wparam, 1 },
1425     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
1426     { WM_SIZE, sent },
1427
1428      /* in MDI child */
1429     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOZORDER },
1430     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
1431     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
1432     { WM_SIZE, sent|defwinproc },
1433
1434      /* in MDI frame */
1435     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1436     { WM_NCCALCSIZE, sent|wparam, 1 },
1437     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1438
1439     { WM_NCACTIVATE, sent|wparam, 0 },
1440     { WM_MDIACTIVATE, sent },
1441
1442     { HCBT_MINMAX, hook },
1443     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|0x8000 },
1444     { WM_NCCALCSIZE, sent|wparam, 1 },
1445     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1446     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE|0x8000 },
1447     { WM_SIZE, sent|defwinproc },
1448
1449      /* in MDI child */
1450     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1451     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
1452     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1453
1454      /* in MDI frame */
1455     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1456     { WM_NCCALCSIZE, sent|wparam, 1 },
1457     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1458     { WM_MOVE, sent|defwinproc },
1459     { WM_SIZE, sent|defwinproc },
1460
1461      /* in MDI client */
1462     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
1463     { WM_NCCALCSIZE, sent|wparam, 1 },
1464     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
1465     { WM_SIZE, sent },
1466
1467     { HCBT_SETFOCUS, hook },
1468     { WM_KILLFOCUS, sent },
1469     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1470     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1471     { WM_SETFOCUS, sent }, /* in MDI client */
1472
1473     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
1474
1475     { HCBT_DESTROYWND, hook },
1476     /* Win2k sends wparam set to
1477      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1478      * while Win9x doesn't bother to set child window id according to
1479      * CLIENTCREATESTRUCT.idFirstChild
1480      */
1481     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1482
1483     { WM_SHOWWINDOW, sent|wparam, 0 },
1484     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1485     { WM_ERASEBKGND, sent|parent|optional },
1486     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1487
1488     { WM_DESTROY, sent },
1489     { WM_NCDESTROY, sent },
1490     { 0 }
1491 };
1492 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
1493 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
1494     { HCBT_MINMAX, hook },
1495     { WM_GETMINMAXINFO, sent },
1496     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
1497     { WM_NCCALCSIZE, sent|wparam, 1 },
1498     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1499
1500     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1501     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1502     { HCBT_SETFOCUS, hook },
1503     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1504     { WM_SETFOCUS, sent }, /* in MDI client */
1505     { HCBT_SETFOCUS, hook },
1506     { WM_KILLFOCUS, sent }, /* in MDI client */
1507     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1508     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1509     { WM_SETFOCUS, sent|defwinproc },
1510     { WM_MDIACTIVATE, sent|defwinproc },
1511     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1512     { WM_SIZE, sent|defwinproc },
1513      /* in MDI frame */
1514     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1515     { WM_NCCALCSIZE, sent|wparam, 1 },
1516     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1517     { 0 }
1518 };
1519 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
1520 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
1521     { HCBT_MINMAX, hook },
1522     { WM_GETMINMAXINFO, sent },
1523     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
1524     { WM_NCCALCSIZE, sent|wparam, 1 },
1525     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1526     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1527     { WM_SIZE, sent|defwinproc },
1528      /* in MDI frame */
1529     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1530     { WM_NCCALCSIZE, sent|wparam, 1 },
1531     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1532     { 0 }
1533 };
1534 /* ShowWindow(SW_RESTORE) for a visible MDI child window */
1535 static const struct message WmRestoreMDIchildVisibleSeq[] = {
1536     { HCBT_MINMAX, hook },
1537     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
1538     { WM_NCCALCSIZE, sent|wparam, 1 },
1539     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1540     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1541     { WM_SIZE, sent|defwinproc },
1542      /* in MDI frame */
1543     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1544     { WM_NCCALCSIZE, sent|wparam, 1 },
1545     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1546     { 0 }
1547 };
1548 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
1549 static const struct message WmRestoreMDIchildInisibleSeq[] = {
1550     { HCBT_MINMAX, hook },
1551     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
1552     { WM_NCCALCSIZE, sent|wparam, 1 },
1553     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1554     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1555     { WM_SIZE, sent|defwinproc },
1556      /* in MDI frame */
1557     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1558     { WM_NCCALCSIZE, sent|wparam, 1 },
1559     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1560     { 0 }
1561 };
1562
1563 static HWND mdi_client;
1564 static WNDPROC old_mdi_client_proc;
1565
1566 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1567 {
1568     struct message msg;
1569
1570     /* do not log painting messages */
1571     if (message != WM_PAINT &&
1572         message != WM_ERASEBKGND &&
1573         message != WM_NCPAINT &&
1574         message != WM_GETTEXT &&
1575         message != WM_MDIGETACTIVE)
1576     {
1577         trace("mdi client: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1578
1579         switch (message)
1580         {
1581             case WM_WINDOWPOSCHANGING:
1582             case WM_WINDOWPOSCHANGED:
1583             {
1584                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
1585
1586                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
1587                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
1588                       winpos->hwnd, winpos->hwndInsertAfter,
1589                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
1590
1591                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
1592                  * in the high word for internal purposes
1593                  */
1594                 wParam = winpos->flags & 0xffff;
1595                 break;
1596             }
1597         }
1598
1599         msg.message = message;
1600         msg.flags = sent|wparam|lparam;
1601         msg.wParam = wParam;
1602         msg.lParam = lParam;
1603         add_message(&msg);
1604     }
1605
1606     return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
1607 }
1608
1609 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1610 {
1611     static long defwndproc_counter = 0;
1612     LRESULT ret;
1613     struct message msg;
1614
1615     /* do not log painting messages */
1616     if (message != WM_PAINT &&
1617         message != WM_ERASEBKGND &&
1618         message != WM_NCPAINT &&
1619         message != WM_GETTEXT)
1620     {
1621         trace("mdi child: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1622
1623         switch (message)
1624         {
1625             case WM_WINDOWPOSCHANGING:
1626             case WM_WINDOWPOSCHANGED:
1627             {
1628                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
1629
1630                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
1631                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
1632                       winpos->hwnd, winpos->hwndInsertAfter,
1633                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
1634
1635                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
1636                  * in the high word for internal purposes
1637                  */
1638                 wParam = winpos->flags & 0xffff;
1639                 break;
1640             }
1641
1642             case WM_MDIACTIVATE:
1643             {
1644                 HWND active, client = GetParent(hwnd);
1645
1646                 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
1647
1648                 if (hwnd == (HWND)lParam) /* if we are being activated */
1649                     ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
1650                 else
1651                     ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
1652                 break;
1653             }
1654         }
1655
1656         msg.message = message;
1657         msg.flags = sent|wparam|lparam;
1658         if (defwndproc_counter) msg.flags |= defwinproc;
1659         msg.wParam = wParam;
1660         msg.lParam = lParam;
1661         add_message(&msg);
1662     }
1663
1664     defwndproc_counter++;
1665     ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
1666     defwndproc_counter--;
1667
1668     return ret;
1669 }
1670
1671 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1672 {
1673     static long defwndproc_counter = 0;
1674     LRESULT ret;
1675     struct message msg;
1676
1677     /* do not log painting messages */
1678     if (message != WM_PAINT &&
1679         message != WM_ERASEBKGND &&
1680         message != WM_NCPAINT &&
1681         message != WM_GETTEXT)
1682     {
1683         trace("mdi frame: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1684
1685         switch (message)
1686         {
1687             case WM_WINDOWPOSCHANGING:
1688             case WM_WINDOWPOSCHANGED:
1689             {
1690                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
1691
1692                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
1693                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
1694                       winpos->hwnd, winpos->hwndInsertAfter,
1695                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
1696
1697                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
1698                  * in the high word for internal purposes
1699                  */
1700                 wParam = winpos->flags & 0xffff;
1701                 break;
1702             }
1703         }
1704
1705         msg.message = message;
1706         msg.flags = sent|wparam|lparam;
1707         if (defwndproc_counter) msg.flags |= defwinproc;
1708         msg.wParam = wParam;
1709         msg.lParam = lParam;
1710         add_message(&msg);
1711     }
1712
1713     defwndproc_counter++;
1714     ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
1715     defwndproc_counter--;
1716
1717     return ret;
1718 }
1719
1720 static BOOL mdi_RegisterWindowClasses(void)
1721 {
1722     WNDCLASSA cls;
1723
1724     cls.style = 0;
1725     cls.lpfnWndProc = mdi_frame_wnd_proc;
1726     cls.cbClsExtra = 0;
1727     cls.cbWndExtra = 0;
1728     cls.hInstance = GetModuleHandleA(0);
1729     cls.hIcon = 0;
1730     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
1731     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
1732     cls.lpszMenuName = NULL;
1733     cls.lpszClassName = "MDI_frame_class";
1734     if (!RegisterClassA(&cls)) return FALSE;
1735
1736     cls.lpfnWndProc = mdi_child_wnd_proc;
1737     cls.lpszClassName = "MDI_child_class";
1738     if (!RegisterClassA(&cls)) return FALSE;
1739
1740     if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
1741     old_mdi_client_proc = cls.lpfnWndProc;
1742     cls.hInstance = GetModuleHandleA(0);
1743     cls.lpfnWndProc = mdi_client_hook_proc;
1744     cls.lpszClassName = "MDI_client_class";
1745     if (!RegisterClassA(&cls)) assert(0);
1746
1747     return TRUE;
1748 }
1749
1750 static void test_mdi_messages(void)
1751 {
1752     MDICREATESTRUCTA mdi_cs;
1753     CLIENTCREATESTRUCT client_cs;
1754     HWND mdi_frame, mdi_child, mdi_child2, active_child;
1755     BOOL zoomed;
1756     HMENU hMenu = CreateMenu();
1757
1758     assert(mdi_RegisterWindowClasses());
1759
1760     flush_sequence();
1761
1762     trace("creating MDI frame window\n");
1763     mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
1764                                 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
1765                                 WS_MAXIMIZEBOX | WS_VISIBLE,
1766                                 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
1767                                 GetDesktopWindow(), hMenu,
1768                                 GetModuleHandleA(0), NULL);
1769     assert(mdi_frame);
1770     ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", TRUE);
1771
1772     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1773     ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
1774
1775     trace("creating MDI client window\n");
1776     client_cs.hWindowMenu = 0;
1777     client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
1778     mdi_client = CreateWindowExA(0, "MDI_client_class",
1779                                  NULL,
1780                                  WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
1781                                  0, 0, 0, 0,
1782                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
1783     assert(mdi_client);
1784     ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
1785
1786     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1787     ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
1788
1789     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1790     ok(!active_child, "wrong active MDI child %p\n", active_child);
1791     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
1792
1793     SetFocus(0);
1794     flush_sequence();
1795
1796     trace("creating invisible MDI child window\n");
1797     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
1798                                 WS_CHILD,
1799                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
1800                                 mdi_client, 0, GetModuleHandleA(0), NULL);
1801     assert(mdi_child);
1802
1803     flush_sequence();
1804     ShowWindow(mdi_child, SW_SHOWNORMAL);
1805     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
1806
1807     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
1808     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
1809
1810     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1811     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1812
1813     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1814     ok(!active_child, "wrong active MDI child %p\n", active_child);
1815     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
1816
1817     ShowWindow(mdi_child, SW_HIDE);
1818     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
1819     flush_sequence();
1820
1821     ShowWindow(mdi_child, SW_SHOW);
1822     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
1823
1824     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
1825     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
1826
1827     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1828     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1829
1830     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1831     ok(!active_child, "wrong active MDI child %p\n", active_child);
1832     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
1833
1834     DestroyWindow(mdi_child);
1835     flush_sequence();
1836
1837     trace("creating visible MDI child window\n");
1838     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
1839                                 WS_CHILD | WS_VISIBLE,
1840                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
1841                                 mdi_client, 0, GetModuleHandleA(0), NULL);
1842     assert(mdi_child);
1843     ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", TRUE);
1844
1845     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
1846     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
1847
1848     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1849     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
1850
1851     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1852     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
1853     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
1854     flush_sequence();
1855
1856     DestroyWindow(mdi_child);
1857     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
1858
1859     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1860     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1861
1862     /* Win2k: MDI client still returns a just destroyed child as active
1863      * Win9x: MDI client returns 0
1864      */
1865     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1866     ok(active_child == mdi_child || /* win2k */
1867        !active_child, /* win9x */
1868        "wrong active MDI child %p\n", active_child);
1869     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
1870
1871     flush_sequence();
1872
1873     trace("creating invisible MDI child window\n");
1874     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
1875                                 WS_CHILD,
1876                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
1877                                 mdi_client, 0, GetModuleHandleA(0), NULL);
1878     assert(mdi_child2);
1879     ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
1880
1881     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
1882     ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
1883
1884     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1885     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1886
1887     /* Win2k: MDI client still returns a just destroyed child as active
1888      * Win9x: MDI client returns mdi_child2
1889      */
1890     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1891     ok(active_child == mdi_child || /* win2k */
1892        active_child == mdi_child2, /* win9x */
1893        "wrong active MDI child %p\n", active_child);
1894     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
1895     flush_sequence();
1896
1897     ShowWindow(mdi_child2, SW_MAXIMIZE);
1898     ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", TRUE);
1899
1900     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
1901     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
1902
1903     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1904     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
1905     ok(zoomed, "wrong zoomed state %d\n", zoomed);
1906     flush_sequence();
1907
1908     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1909     ok(GetFocus() == mdi_child2 || /* win2k */
1910        GetFocus() == 0, /* win9x */
1911        "wrong focus window %p\n", GetFocus());
1912
1913     SetFocus(0);
1914     flush_sequence();
1915
1916     ShowWindow(mdi_child2, SW_HIDE);
1917     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
1918
1919     ShowWindow(mdi_child2, SW_RESTORE);
1920     ok_sequence(WmRestoreMDIchildInisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", TRUE);
1921     flush_sequence();
1922
1923     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
1924     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
1925
1926     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1927     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
1928     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
1929     flush_sequence();
1930
1931     SetFocus(0);
1932     flush_sequence();
1933
1934     ShowWindow(mdi_child2, SW_HIDE);
1935     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
1936
1937     ShowWindow(mdi_child2, SW_SHOW);
1938     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
1939
1940     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1941     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1942
1943     ShowWindow(mdi_child2, SW_MAXIMIZE);
1944     ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", TRUE);
1945
1946     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1947     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1948
1949     ShowWindow(mdi_child2, SW_RESTORE);
1950     ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):MDI child", TRUE);
1951
1952     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1953     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1954
1955     SetFocus(0);
1956     flush_sequence();
1957
1958     ShowWindow(mdi_child2, SW_HIDE);
1959     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
1960
1961     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1962     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1963
1964     DestroyWindow(mdi_child2);
1965     ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
1966
1967     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1968     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
1969
1970     /* test for maximized MDI children */
1971     trace("creating maximized visible MDI child window 1\n");
1972     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
1973                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
1974                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
1975                                 mdi_client, 0, GetModuleHandleA(0), NULL);
1976     assert(mdi_child);
1977     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
1978     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
1979
1980     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
1981     ok(GetFocus() == mdi_child || /* win2k */
1982        GetFocus() == 0, /* win9x */
1983        "wrong focus window %p\n", GetFocus());
1984
1985     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
1986     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
1987     ok(zoomed, "wrong zoomed state %d\n", zoomed);
1988     flush_sequence();
1989
1990     trace("creating maximized visible MDI child window 2\n");
1991     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
1992                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
1993                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
1994                                 mdi_client, 0, GetModuleHandleA(0), NULL);
1995     assert(mdi_child2);
1996     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
1997     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
1998     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
1999
2000     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2001     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
2002
2003     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2004     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
2005     ok(zoomed, "wrong zoomed state %d\n", zoomed);
2006     flush_sequence();
2007
2008     trace("destroying maximized visible MDI child window 2\n");
2009     DestroyWindow(mdi_child2);
2010     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
2011
2012     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
2013
2014     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2015     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2016
2017     /* Win2k: MDI client still returns a just destroyed child as active
2018      * Win9x: MDI client returns 0
2019      */
2020     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2021     ok(active_child == mdi_child2 || /* win2k */
2022        !active_child, /* win9x */
2023        "wrong active MDI child %p\n", active_child);
2024     flush_sequence();
2025
2026     ShowWindow(mdi_child, SW_MAXIMIZE);
2027     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
2028     flush_sequence();
2029
2030     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2031     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
2032
2033     trace("re-creating maximized visible MDI child window 2\n");
2034     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
2035                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
2036                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
2037                                 mdi_client, 0, GetModuleHandleA(0), NULL);
2038     assert(mdi_child2);
2039     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
2040     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
2041     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
2042
2043     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2044     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
2045
2046     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2047     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
2048     ok(zoomed, "wrong zoomed state %d\n", zoomed);
2049     flush_sequence();
2050
2051     SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
2052     ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
2053     ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
2054
2055     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
2056     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2057     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
2058
2059     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2060     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
2061     ok(zoomed, "wrong zoomed state %d\n", zoomed);
2062     flush_sequence();
2063
2064     DestroyWindow(mdi_child);
2065     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
2066
2067     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2068     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2069
2070     /* Win2k: MDI client still returns a just destroyed child as active
2071      * Win9x: MDI client returns 0
2072      */
2073     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2074     ok(active_child == mdi_child || /* win2k */
2075        !active_child, /* win9x */
2076        "wrong active MDI child %p\n", active_child);
2077     flush_sequence();
2078     /* end of test for maximized MDI children */
2079
2080     mdi_cs.szClass = "MDI_child_Class";
2081     mdi_cs.szTitle = "MDI child";
2082     mdi_cs.hOwner = GetModuleHandleA(0);
2083     mdi_cs.x = 0;
2084     mdi_cs.y = 0;
2085     mdi_cs.cx = CW_USEDEFAULT;
2086     mdi_cs.cy = CW_USEDEFAULT;
2087     mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
2088     mdi_cs.lParam = 0;
2089     mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
2090     ok(mdi_child != 0, "MDI child creation failed\n");
2091     ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
2092
2093     ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
2094
2095     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2096     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
2097
2098     ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
2099     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2100     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
2101
2102     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2103     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
2104     ok(zoomed, "wrong zoomed state %d\n", zoomed);
2105     flush_sequence();
2106
2107     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
2108     ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
2109
2110     ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
2111     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2112     ok(!active_child, "wrong active MDI child %p\n", active_child);
2113
2114     SetFocus(0);
2115     flush_sequence();
2116
2117     DestroyWindow(mdi_client);
2118     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
2119
2120     DestroyWindow(mdi_frame);
2121     ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
2122 }
2123 /************************* End of MDI test **********************************/
2124
2125 static void test_WM_SETREDRAW(HWND hwnd)
2126 {
2127     DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
2128
2129     flush_sequence();
2130
2131     SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
2132     ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
2133
2134     ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
2135     ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
2136
2137     flush_sequence();
2138     SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
2139     ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
2140
2141     ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
2142     ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
2143
2144     /* restore original WS_VISIBLE state */
2145     SetWindowLongA(hwnd, GWL_STYLE, style);
2146
2147     flush_sequence();
2148 }
2149
2150 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2151 {
2152     struct message msg;
2153
2154     trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2155
2156     msg.message = message;
2157     msg.flags = sent|wparam|lparam;
2158     msg.wParam = wParam;
2159     msg.lParam = lParam;
2160     add_message(&msg);
2161
2162     if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
2163     if (message == WM_TIMER) EndDialog( hwnd, 0 );
2164     return 0;
2165 }
2166
2167 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
2168 {
2169     DWORD style, exstyle;
2170     INT xmin, xmax;
2171
2172     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
2173     style = GetWindowLongA(hwnd, GWL_STYLE);
2174     /* do not be confused by WS_DLGFRAME set */
2175     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
2176
2177     if (clear) ok(style & clear, "style %08lx should be set\n", clear);
2178     if (set) ok(!(style & set), "style %08lx should not be set\n", set);
2179
2180     ok(SetScrollRange(hwnd, ctl, min, max, FALSE), "SetScrollRange(%d) error %ld\n", ctl, GetLastError());
2181     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
2182         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
2183     else
2184         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
2185
2186     style = GetWindowLongA(hwnd, GWL_STYLE);
2187     if (set) ok(style & set, "style %08lx should be set\n", set);
2188     if (clear) ok(!(style & clear), "style %08lx should not be set\n", clear);
2189
2190     /* a subsequent call should do nothing */
2191     ok(SetScrollRange(hwnd, ctl, min, max, FALSE), "SetScrollRange(%d) error %ld\n", ctl, GetLastError());
2192     ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
2193
2194     xmin = 0xdeadbeef;
2195     xmax = 0xdeadbeef;
2196     trace("Ignore GetScrollRange error below if you are on Win9x\n");
2197     ok(GetScrollRange(hwnd, ctl, &xmin, &xmax), "GetScrollRange(%d) error %ld\n", ctl, GetLastError());
2198     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT)", FALSE);
2199     ok(xmin == min, "unexpected min scroll value %d\n", xmin);
2200     ok(xmax == max, "unexpected max scroll value %d\n", xmax);
2201 }
2202
2203 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
2204 {
2205     DWORD style, exstyle;
2206     SCROLLINFO si;
2207
2208     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
2209     style = GetWindowLongA(hwnd, GWL_STYLE);
2210     /* do not be confused by WS_DLGFRAME set */
2211     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
2212
2213     if (clear) ok(style & clear, "style %08lx should be set\n", clear);
2214     if (set) ok(!(style & set), "style %08lx should not be set\n", set);
2215
2216     si.cbSize = sizeof(si);
2217     si.fMask = SIF_RANGE;
2218     si.nMin = min;
2219     si.nMax = max;
2220     SetScrollInfo(hwnd, ctl, &si, TRUE);
2221     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
2222         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
2223     else
2224         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
2225
2226     style = GetWindowLongA(hwnd, GWL_STYLE);
2227     if (set) ok(style & set, "style %08lx should be set\n", set);
2228     if (clear) ok(!(style & clear), "style %08lx should not be set\n", clear);
2229
2230     /* a subsequent call should do nothing */
2231     SetScrollInfo(hwnd, ctl, &si, TRUE);
2232     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
2233
2234     si.fMask = SIF_PAGE;
2235     si.nPage = 5;
2236     SetScrollInfo(hwnd, ctl, &si, FALSE);
2237     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
2238
2239     si.fMask = SIF_POS;
2240     si.nPos = max - 1;
2241     SetScrollInfo(hwnd, ctl, &si, FALSE);
2242     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
2243
2244     si.fMask = SIF_RANGE;
2245     si.nMin = 0xdeadbeef;
2246     si.nMax = 0xdeadbeef;
2247     ok(GetScrollInfo(hwnd, ctl, &si), "GetScrollInfo error %ld\n", GetLastError());
2248     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT)", FALSE);
2249     ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
2250     ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
2251 }
2252
2253 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
2254 static void test_scroll_messages(HWND hwnd)
2255 {
2256     SCROLLINFO si;
2257     INT min, max;
2258
2259     min = 0xdeadbeef;
2260     max = 0xdeadbeef;
2261     ok(GetScrollRange(hwnd, SB_CTL, &min, &max), "GetScrollRange error %ld\n", GetLastError());
2262     if (sequence->message != WmGetScrollRangeSeq[0].message)
2263         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
2264     /* values of min and max are undefined */
2265     flush_sequence();
2266
2267     ok(SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE), "SetScrollRange error %ld\n", GetLastError());
2268     if (sequence->message != WmSetScrollRangeSeq[0].message)
2269         trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
2270     flush_sequence();
2271
2272     min = 0xdeadbeef;
2273     max = 0xdeadbeef;
2274     ok(GetScrollRange(hwnd, SB_CTL, &min, &max), "GetScrollRange error %ld\n", GetLastError());
2275     if (sequence->message != WmGetScrollRangeSeq[0].message)
2276         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
2277     /* values of min and max are undefined */
2278     flush_sequence();
2279
2280     si.cbSize = sizeof(si);
2281     si.fMask = SIF_RANGE;
2282     si.nMin = 20;
2283     si.nMax = 160;
2284     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
2285     if (sequence->message != WmSetScrollRangeSeq[0].message)
2286         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
2287     flush_sequence();
2288
2289     si.fMask = SIF_PAGE;
2290     si.nPage = 10;
2291     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
2292     if (sequence->message != WmSetScrollRangeSeq[0].message)
2293         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
2294     flush_sequence();
2295
2296     si.fMask = SIF_POS;
2297     si.nPos = 20;
2298     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
2299     if (sequence->message != WmSetScrollRangeSeq[0].message)
2300         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
2301     flush_sequence();
2302
2303     si.fMask = SIF_RANGE;
2304     si.nMin = 0xdeadbeef;
2305     si.nMax = 0xdeadbeef;
2306     ok(GetScrollInfo(hwnd, SB_CTL, &si), "GetScrollInfo error %ld\n", GetLastError());
2307     if (sequence->message != WmGetScrollInfoSeq[0].message)
2308         trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
2309     /* values of min and max are undefined */
2310     flush_sequence();
2311
2312     /* set WS_HSCROLL */
2313     test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
2314     /* clear WS_HSCROLL */
2315     test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
2316
2317     /* set WS_HSCROLL */
2318     test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
2319     /* clear WS_HSCROLL */
2320     test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
2321
2322     /* set WS_VSCROLL */
2323     test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
2324     /* clear WS_VSCROLL */
2325     test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
2326
2327     /* set WS_VSCROLL */
2328     test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
2329     /* clear WS_VSCROLL */
2330     test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
2331 }
2332
2333 /* test if we receive the right sequence of messages */
2334 static void test_messages(void)
2335 {
2336     HWND hwnd, hparent, hchild;
2337     HWND hchild2, hbutton;
2338     HMENU hmenu;
2339     MSG msg;
2340
2341     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
2342                            100, 100, 200, 200, 0, 0, 0, NULL);
2343     ok (hwnd != 0, "Failed to create overlapped window\n");
2344     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
2345
2346     /* test ShowWindow(SW_HIDE) on a newly created invisible window */
2347     ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
2348     ok_sequence(WmHideInvisibleOverlappedSeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
2349
2350     /* test WM_SETREDRAW on a not visible top level window */
2351     test_WM_SETREDRAW(hwnd);
2352
2353     SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
2354     ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
2355     ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
2356
2357     ok(GetActiveWindow() == hwnd, "window should be active\n");
2358     ok(GetFocus() == hwnd, "window should have input focus\n");
2359     ShowWindow(hwnd, SW_HIDE);
2360     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", TRUE);
2361     
2362     ShowWindow(hwnd, SW_SHOW);
2363     ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
2364
2365     ok(GetActiveWindow() == hwnd, "window should be active\n");
2366     ok(GetFocus() == hwnd, "window should have input focus\n");
2367     SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
2368     ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
2369     ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
2370
2371     /* test WM_SETREDRAW on a visible top level window */
2372     ShowWindow(hwnd, SW_SHOW);
2373     test_WM_SETREDRAW(hwnd);
2374
2375     trace("testing scroll APIs on a visible top level window %p\n", hwnd);
2376     test_scroll_messages(hwnd);
2377
2378     DestroyWindow(hwnd);
2379     ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
2380
2381     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
2382                               100, 100, 200, 200, 0, 0, 0, NULL);
2383     ok (hparent != 0, "Failed to create parent window\n");
2384     flush_sequence();
2385
2386     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
2387                              0, 0, 10, 10, hparent, 0, 0, NULL);
2388     ok (hchild != 0, "Failed to create child window\n");
2389     ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", TRUE);
2390     DestroyWindow(hchild);
2391     flush_sequence();
2392
2393     /* visible child window with a caption */
2394     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
2395                              WS_CHILD | WS_VISIBLE | WS_CAPTION,
2396                              0, 0, 10, 10, hparent, 0, 0, NULL);
2397     ok (hchild != 0, "Failed to create child window\n");
2398     ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
2399
2400     trace("testing scroll APIs on a visible child window %p\n", hchild);
2401     test_scroll_messages(hchild);
2402
2403     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
2404     ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
2405
2406     DestroyWindow(hchild);
2407     flush_sequence();
2408
2409     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
2410                              0, 0, 10, 10, hparent, 0, 0, NULL);
2411     ok (hchild != 0, "Failed to create child window\n");
2412     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
2413     
2414     hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
2415                                100, 100, 50, 50, hparent, 0, 0, NULL);
2416     ok (hchild2 != 0, "Failed to create child2 window\n");
2417     flush_sequence();
2418
2419     hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
2420                               0, 100, 50, 50, hchild, 0, 0, NULL);
2421     ok (hbutton != 0, "Failed to create button window\n");
2422
2423     /* test WM_SETREDRAW on a not visible child window */
2424     test_WM_SETREDRAW(hchild);
2425
2426     ShowWindow(hchild, SW_SHOW);
2427     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
2428
2429     ShowWindow(hchild, SW_HIDE);
2430     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
2431
2432     ShowWindow(hchild, SW_SHOW);
2433     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
2434
2435     /* test WM_SETREDRAW on a visible child window */
2436     test_WM_SETREDRAW(hchild);
2437
2438     MoveWindow(hchild, 10, 10, 20, 20, TRUE);
2439     ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
2440
2441     ShowWindow(hchild, SW_HIDE);
2442     flush_sequence();
2443     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
2444     ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
2445
2446     ShowWindow(hchild, SW_HIDE);
2447     flush_sequence();
2448     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
2449     ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
2450
2451     /* DestroyWindow sequence below expects that a child has focus */
2452     SetFocus(hchild);
2453     flush_sequence();
2454
2455     DestroyWindow(hchild);
2456     ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
2457     DestroyWindow(hchild2);
2458     DestroyWindow(hbutton);
2459
2460     flush_sequence();
2461     hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
2462                              0, 0, 100, 100, hparent, 0, 0, NULL);
2463     ok (hchild != 0, "Failed to create child popup window\n");
2464     ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
2465     DestroyWindow(hchild);
2466
2467     /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
2468     flush_sequence();
2469     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
2470                              0, 0, 100, 100, hparent, 0, 0, NULL);
2471     ok (hchild != 0, "Failed to create popup window\n");
2472     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
2473     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
2474     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
2475     flush_sequence();
2476     ShowWindow(hchild, SW_SHOW);
2477     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
2478     flush_sequence();
2479     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
2480     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
2481     flush_sequence();
2482     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
2483     ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
2484     DestroyWindow(hchild);
2485
2486     /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
2487      * changes nothing in message sequences.
2488      */
2489     flush_sequence();
2490     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
2491                              0, 0, 100, 100, hparent, 0, 0, NULL);
2492     ok (hchild != 0, "Failed to create popup window\n");
2493     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
2494     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
2495     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
2496     flush_sequence();
2497     ShowWindow(hchild, SW_SHOW);
2498     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
2499     flush_sequence();
2500     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
2501     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
2502     DestroyWindow(hchild);
2503
2504     flush_sequence();
2505     hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
2506                            0, 0, 100, 100, hparent, 0, 0, NULL);
2507     ok(hwnd != 0, "Failed to create custom dialog window\n");
2508     ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
2509
2510     trace("testing scroll APIs on a visible dialog %p\n", hwnd);
2511     test_scroll_messages(hwnd);
2512
2513     flush_sequence();
2514     after_end_dialog = 1;
2515     EndDialog( hwnd, 0 );
2516     ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
2517
2518     DestroyWindow(hwnd);
2519     after_end_dialog = 0;
2520
2521     flush_sequence();
2522     DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
2523     ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
2524
2525     /* test showing child with hidden parent */
2526     ShowWindow( hparent, SW_HIDE );
2527     flush_sequence();
2528
2529     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
2530                              0, 0, 10, 10, hparent, 0, 0, NULL);
2531     ok (hchild != 0, "Failed to create child window\n");
2532     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
2533
2534     ShowWindow( hchild, SW_SHOW );
2535     ok_sequence(WmShowChildInvisibleParentSeq, "ShowWindow:show child with invisible parent", TRUE);
2536     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
2537     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
2538
2539     ShowWindow( hchild, SW_HIDE );
2540     ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", TRUE);
2541     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
2542     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
2543
2544     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
2545     ok_sequence(WmShowChildInvisibleParentSeq_2, "SetWindowPos:show child with invisible parent", TRUE);
2546     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
2547     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
2548
2549     SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
2550     ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", TRUE);
2551     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
2552     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
2553
2554     DestroyWindow(hchild);
2555     DestroyWindow(hparent);
2556     flush_sequence();
2557
2558     /* Message sequence for SetMenu */
2559     ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a window without a menu\n");
2560     ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
2561
2562     hmenu = CreateMenu();
2563     ok (hmenu != 0, "Failed to create menu\n");
2564     ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
2565     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
2566                            100, 100, 200, 200, 0, hmenu, 0, NULL);
2567     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
2568     ok (SetMenu(hwnd, 0), "SetMenu\n");
2569     ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
2570     ok (SetMenu(hwnd, 0), "SetMenu\n");
2571     ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
2572     ShowWindow(hwnd, SW_SHOW);
2573     flush_sequence();
2574     ok (SetMenu(hwnd, 0), "SetMenu\n");
2575     ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", TRUE);
2576     ok (SetMenu(hwnd, hmenu), "SetMenu\n");
2577     ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", TRUE);
2578
2579     ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
2580     ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", TRUE);
2581
2582     DestroyWindow(hwnd);
2583     flush_sequence();
2584
2585     /* Message sequence for EnableWindow */
2586     hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
2587                               100, 100, 200, 200, 0, 0, 0, NULL);
2588     ok (hparent != 0, "Failed to create parent window\n");
2589     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
2590                              0, 0, 10, 10, hparent, 0, 0, NULL);
2591     ok (hchild != 0, "Failed to create child window\n");
2592
2593     SetFocus(hchild);
2594     flush_sequence();
2595
2596     EnableWindow(hparent, FALSE);
2597     ok_sequence(WmEnableWindowSeq, "EnableWindow", FALSE);
2598
2599     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
2600     flush_sequence();
2601     PostMessage( hparent, WM_USER, 0, 0 );
2602     PostMessage( hparent, WM_USER+1, 0, 0 );
2603     /* PeekMessage(NULL) fails, but still removes the message */
2604     SetLastError(0xdeadbeef);
2605     ok( !PeekMessage( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
2606     ok( GetLastError() == ERROR_NOACCESS, "last error is %ld\n", GetLastError() );
2607     ok( PeekMessage( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
2608     ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
2609
2610     DestroyWindow(hchild);
2611     DestroyWindow(hparent);
2612     flush_sequence();
2613 }
2614
2615 /****************** button message test *************************/
2616 static const struct message WmSetFocusButtonSeq[] =
2617 {
2618     { HCBT_SETFOCUS, hook },
2619     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2620     { WM_SETFOCUS, sent|wparam, 0 },
2621     { WM_CTLCOLORBTN, sent|defwinproc },
2622     { 0 }
2623 };
2624 static const struct message WmKillFocusButtonSeq[] =
2625 {
2626     { HCBT_SETFOCUS, hook },
2627     { WM_KILLFOCUS, sent|wparam, 0 },
2628     { WM_CTLCOLORBTN, sent|defwinproc },
2629     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2630     { 0 }
2631 };
2632 static const struct message WmSetFocusStaticSeq[] =
2633 {
2634     { HCBT_SETFOCUS, hook },
2635     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2636     { WM_SETFOCUS, sent|wparam, 0 },
2637     { WM_CTLCOLORSTATIC, sent|defwinproc },
2638     { 0 }
2639 };
2640 static const struct message WmKillFocusStaticSeq[] =
2641 {
2642     { HCBT_SETFOCUS, hook },
2643     { WM_KILLFOCUS, sent|wparam, 0 },
2644     { WM_CTLCOLORSTATIC, sent|defwinproc },
2645     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2646     { 0 }
2647 };
2648 static const struct message WmLButtonDownSeq[] =
2649 {
2650     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
2651     { HCBT_SETFOCUS, hook },
2652     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2653     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
2654     { WM_CTLCOLORBTN, sent|defwinproc },
2655     { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
2656     { WM_CTLCOLORBTN, sent|defwinproc },
2657     { 0 }
2658 };
2659 static const struct message WmLButtonUpSeq[] =
2660 {
2661     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
2662     { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
2663     { WM_CTLCOLORBTN, sent|defwinproc },
2664     { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
2665     { 0 }
2666 };
2667
2668 static WNDPROC old_button_proc;
2669
2670 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2671 {
2672     static long defwndproc_counter = 0;
2673     LRESULT ret;
2674     struct message msg;
2675
2676     trace("button: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2677
2678     msg.message = message;
2679     msg.flags = sent|wparam|lparam;
2680     if (defwndproc_counter) msg.flags |= defwinproc;
2681     msg.wParam = wParam;
2682     msg.lParam = lParam;
2683     add_message(&msg);
2684
2685     if (message == BM_SETSTATE)
2686         ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
2687
2688     defwndproc_counter++;
2689     ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
2690     defwndproc_counter--;
2691
2692     return ret;
2693 }
2694
2695 static void subclass_button(void)
2696 {
2697     WNDCLASSA cls;
2698
2699     if (!GetClassInfoA(0, "button", &cls)) assert(0);
2700
2701     old_button_proc = cls.lpfnWndProc;
2702
2703     cls.hInstance = GetModuleHandle(0);
2704     cls.lpfnWndProc = button_hook_proc;
2705     cls.lpszClassName = "my_button_class";
2706     if (!RegisterClassA(&cls)) assert(0);
2707 }
2708
2709 static void test_button_messages(void)
2710 {
2711     static const struct
2712     {
2713         DWORD style;
2714         DWORD dlg_code;
2715         const struct message *setfocus;
2716         const struct message *killfocus;
2717     } button[] = {
2718         { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
2719           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
2720         { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
2721           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
2722         { BS_CHECKBOX, DLGC_BUTTON,
2723           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2724         { BS_AUTOCHECKBOX, DLGC_BUTTON,
2725           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2726         { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
2727           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2728         { BS_3STATE, DLGC_BUTTON,
2729           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2730         { BS_AUTO3STATE, DLGC_BUTTON,
2731           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2732         { BS_GROUPBOX, DLGC_STATIC,
2733           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2734         { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
2735           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
2736         { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
2737           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
2738         { BS_OWNERDRAW, DLGC_BUTTON,
2739           WmSetFocusButtonSeq, WmKillFocusButtonSeq }
2740     };
2741     unsigned int i;
2742     HWND hwnd;
2743     DWORD dlg_code;
2744
2745     subclass_button();
2746
2747     for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
2748     {
2749         hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP,
2750                                0, 0, 50, 14, 0, 0, 0, NULL);
2751         ok(hwnd != 0, "Failed to create button window\n");
2752
2753         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
2754         ok(dlg_code == button[i].dlg_code, "%d: wrong dlg_code %08lx\n", i, dlg_code);
2755
2756         ShowWindow(hwnd, SW_SHOW);
2757         UpdateWindow(hwnd);
2758         SetFocus(0);
2759         flush_sequence();
2760
2761         trace("button style %08lx\n", button[i].style);
2762         SetFocus(hwnd);
2763         ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
2764
2765         SetFocus(0);
2766         ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
2767
2768         DestroyWindow(hwnd);
2769     }
2770
2771     hwnd = CreateWindowExA(0, "my_button_class", "test", BS_PUSHBUTTON | WS_POPUP | WS_VISIBLE,
2772                            0, 0, 50, 14, 0, 0, 0, NULL);
2773     ok(hwnd != 0, "Failed to create button window\n");
2774
2775     SetFocus(0);
2776     flush_sequence();
2777
2778     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
2779     ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
2780
2781     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
2782     ok_sequence(WmLButtonUpSeq, "WM_LBUTTONDOWN on a button", FALSE);
2783     DestroyWindow(hwnd);
2784 }
2785
2786 /************* painting message test ********************/
2787
2788 static void dump_region(HRGN hrgn)
2789 {
2790     DWORD i, size;
2791     RGNDATA *data = NULL;
2792     RECT *rect;
2793
2794     if (!hrgn)
2795     {
2796         printf( "null region\n" );
2797         return;
2798     }
2799     if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
2800     if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
2801     GetRegionData( hrgn, size, data );
2802     printf("%ld rects:", data->rdh.nCount );
2803     for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
2804         printf( " (%ld,%ld)-(%ld,%ld)", rect->left, rect->top, rect->right, rect->bottom );
2805     printf("\n");
2806     HeapFree( GetProcessHeap(), 0, data );
2807 }
2808
2809 static void check_update_rgn( HWND hwnd, HRGN hrgn )
2810 {
2811     INT ret;
2812     RECT r1, r2;
2813     HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
2814     HRGN update = CreateRectRgn( 0, 0, 0, 0 );
2815
2816     ret = GetUpdateRgn( hwnd, update, FALSE );
2817     ok( ret != ERROR, "GetUpdateRgn failed\n" );
2818     if (ret == NULLREGION)
2819     {
2820         ok( !hrgn, "Update region shouldn't be empty\n" );
2821     }
2822     else
2823     {
2824         if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
2825         {
2826             ok( 0, "Regions are different\n" );
2827             if (winetest_debug > 0)
2828             {
2829                 printf( "Update region: " );
2830                 dump_region( update );
2831                 printf( "Wanted region: " );
2832                 dump_region( hrgn );
2833             }
2834         }
2835     }
2836     GetRgnBox( update, &r1 );
2837     GetUpdateRect( hwnd, &r2, FALSE );
2838     ok( r1.left == r2.left && r1.top == r2.top && r1.right == r2.right && r1.bottom == r2.bottom,
2839         "Rectangles are different: %ld,%ld-%ld,%ld / %ld,%ld-%ld,%ld\n",
2840         r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom );
2841
2842     DeleteObject( tmp );
2843     DeleteObject( update );
2844 }
2845
2846 static const struct message WmInvalidateRgn[] = {
2847     { WM_NCPAINT, sent },
2848     { WM_GETTEXT, sent|defwinproc|optional },
2849     { 0 }
2850 };
2851
2852 static const struct message WmGetUpdateRect[] = {
2853     { WM_NCPAINT, sent },
2854     { WM_GETTEXT, sent|defwinproc|optional },
2855     { WM_PAINT, sent },
2856     { 0 }
2857 };
2858
2859 static const struct message WmInvalidateFull[] = {
2860     { WM_NCPAINT, sent|wparam, 1 },
2861     { WM_GETTEXT, sent|defwinproc|optional },
2862     { 0 }
2863 };
2864
2865 static const struct message WmInvalidateErase[] = {
2866     { WM_NCPAINT, sent|wparam, 1 },
2867     { WM_GETTEXT, sent|defwinproc|optional },
2868     { WM_ERASEBKGND, sent },
2869     { 0 }
2870 };
2871
2872 static const struct message WmInvalidatePaint[] = {
2873     { WM_PAINT, sent },
2874     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
2875     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
2876     { 0 }
2877 };
2878
2879 static const struct message WmInvalidateErasePaint[] = {
2880     { WM_PAINT, sent },
2881     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
2882     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
2883     { WM_ERASEBKGND, sent|beginpaint },
2884     { 0 }
2885 };
2886
2887 static const struct message WmInvalidateErasePaint2[] = {
2888     { WM_PAINT, sent },
2889     { WM_NCPAINT, sent|beginpaint },
2890     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
2891     { WM_ERASEBKGND, sent|beginpaint },
2892     { 0 }
2893 };
2894
2895 static const struct message WmErase[] = {
2896     { WM_ERASEBKGND, sent },
2897     { 0 }
2898 };
2899
2900 static const struct message WmPaint[] = {
2901     { WM_PAINT, sent },
2902     { 0 }
2903 };
2904
2905 static const struct message WmParentOnlyPaint[] = {
2906     { WM_PAINT, sent|parent },
2907     { 0 }
2908 };
2909
2910 static const struct message WmInvalidateParent[] = {
2911     { WM_NCPAINT, sent|parent },
2912     { WM_GETTEXT, sent|defwinproc|parent|optional },
2913     { WM_ERASEBKGND, sent|parent },
2914     { 0 }
2915 };
2916
2917 static const struct message WmInvalidateParentChild[] = {
2918     { WM_NCPAINT, sent|parent },
2919     { WM_GETTEXT, sent|defwinproc|parent|optional },
2920     { WM_ERASEBKGND, sent|parent },
2921     { WM_NCPAINT, sent },
2922     { WM_GETTEXT, sent|defwinproc|optional },
2923     { WM_ERASEBKGND, sent },
2924     { 0 }
2925 };
2926
2927 static const struct message WmInvalidateParentChild2[] = {
2928     { WM_ERASEBKGND, sent|parent },
2929     { WM_NCPAINT, sent },
2930     { WM_GETTEXT, sent|defwinproc|optional },
2931     { WM_ERASEBKGND, sent },
2932     { 0 }
2933 };
2934
2935 static const struct message WmParentPaint[] = {
2936     { WM_PAINT, sent|parent },
2937     { WM_PAINT, sent },
2938     { 0 }
2939 };
2940
2941 static const struct message WmParentPaintNc[] = {
2942     { WM_PAINT, sent|parent },
2943     { WM_PAINT, sent },
2944     { WM_NCPAINT, sent|beginpaint },
2945     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
2946     { WM_ERASEBKGND, sent|beginpaint },
2947     { 0 }
2948 };
2949
2950 static const struct message WmChildPaintNc[] = {
2951     { WM_PAINT, sent },
2952     { WM_NCPAINT, sent|beginpaint },
2953     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
2954     { WM_ERASEBKGND, sent|beginpaint },
2955     { 0 }
2956 };
2957
2958 static const struct message WmParentErasePaint[] = {
2959     { WM_PAINT, sent|parent },
2960     { WM_NCPAINT, sent|parent|beginpaint },
2961     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
2962     { WM_ERASEBKGND, sent|parent|beginpaint },
2963     { WM_PAINT, sent },
2964     { WM_NCPAINT, sent|beginpaint },
2965     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
2966     { WM_ERASEBKGND, sent|beginpaint },
2967     { 0 }
2968 };
2969
2970 static const struct message WmParentOnlyNcPaint[] = {
2971     { WM_PAINT, sent|parent },
2972     { WM_NCPAINT, sent|parent|beginpaint },
2973     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
2974     { 0 }
2975 };
2976
2977 static const struct message WmSetParentStyle[] = {
2978     { WM_STYLECHANGING, sent|parent },
2979     { WM_STYLECHANGED, sent|parent },
2980     { 0 }
2981 };
2982
2983 static void test_paint_messages(void)
2984 {
2985     RECT rect;
2986     POINT pt;
2987     MSG msg;
2988     HWND hparent, hchild;
2989     HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
2990     HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
2991     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
2992                                 100, 100, 200, 200, 0, 0, 0, NULL);
2993     ok (hwnd != 0, "Failed to create overlapped window\n");
2994
2995     ShowWindow( hwnd, SW_SHOW );
2996     UpdateWindow( hwnd );
2997
2998     /* try to flush pending X expose events */
2999     MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
3000     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3001
3002     check_update_rgn( hwnd, 0 );
3003     SetRectRgn( hrgn, 10, 10, 20, 20 );
3004     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
3005     check_update_rgn( hwnd, hrgn );
3006     SetRectRgn( hrgn2, 20, 20, 30, 30 );
3007     RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
3008     CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
3009     check_update_rgn( hwnd, hrgn );
3010     /* validate everything */
3011     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
3012     check_update_rgn( hwnd, 0 );
3013     /* now with frame */
3014     SetRectRgn( hrgn, -5, -5, 20, 20 );
3015
3016     /* flush pending messages */
3017     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3018
3019     flush_sequence();
3020     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
3021     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
3022
3023     SetRectRgn( hrgn, 0, 0, 20, 20 );  /* GetUpdateRgn clips to client area */
3024     check_update_rgn( hwnd, hrgn );
3025
3026     flush_sequence();
3027     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
3028     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
3029
3030     flush_sequence();
3031     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
3032     ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
3033
3034     GetClientRect( hwnd, &rect );
3035     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
3036     check_update_rgn( hwnd, hrgn );
3037
3038     flush_sequence();
3039     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
3040     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
3041
3042     flush_sequence();
3043     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
3044     ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
3045     check_update_rgn( hwnd, 0 );
3046
3047     flush_sequence();
3048     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
3049     ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
3050     check_update_rgn( hwnd, 0 );
3051
3052     flush_sequence();
3053     SetRectRgn( hrgn, 0, 0, 100, 100 );
3054     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
3055     SetRectRgn( hrgn, 0, 0, 50, 100 );
3056     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
3057     SetRectRgn( hrgn, 50, 0, 100, 100 );
3058     check_update_rgn( hwnd, hrgn );
3059     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
3060     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );  /* must not generate messages, everything is valid */
3061     check_update_rgn( hwnd, 0 );
3062
3063     flush_sequence();
3064     SetRectRgn( hrgn, 0, 0, 100, 100 );
3065     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
3066     SetRectRgn( hrgn, 0, 0, 100, 50 );
3067     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
3068     ok_sequence( WmErase, "Erase", FALSE );
3069     SetRectRgn( hrgn, 0, 50, 100, 100 );
3070     check_update_rgn( hwnd, hrgn );
3071
3072     flush_sequence();
3073     SetRectRgn( hrgn, 0, 0, 100, 100 );
3074     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
3075     SetRectRgn( hrgn, 0, 0, 50, 50 );
3076     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
3077     ok_sequence( WmPaint, "Paint", FALSE );
3078
3079     flush_sequence();
3080     SetRectRgn( hrgn, -4, -4, -2, -2 );
3081     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
3082     SetRectRgn( hrgn, -200, -200, -198, -198 );
3083     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
3084     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
3085
3086     flush_sequence();
3087     SetRectRgn( hrgn, -4, -4, -2, -2 );
3088     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
3089     SetRectRgn( hrgn, -4, -4, -3, -3 );
3090     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
3091     SetRectRgn( hrgn, 0, 0, 1, 1 );
3092     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
3093     ok_sequence( WmPaint, "Paint", FALSE );
3094
3095     flush_sequence();
3096     SetRectRgn( hrgn, -4, -4, -1, -1 );
3097     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
3098     RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
3099     /* make sure no WM_PAINT was generated */
3100     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3101     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
3102
3103     flush_sequence();
3104     SetRectRgn( hrgn, -4, -4, -1, -1 );
3105     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
3106     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
3107     {
3108         if (msg.hwnd == hwnd && msg.message == WM_PAINT)
3109         {
3110             /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
3111             INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
3112             ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
3113             ret = GetUpdateRect( hwnd, &rect, FALSE );
3114             ok( ret, "Invalid GetUpdateRect result %d\n", ret );
3115             /* this will send WM_NCPAINT and validate the non client area */
3116             ret = GetUpdateRect( hwnd, &rect, TRUE );
3117             ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
3118         }
3119         DispatchMessage( &msg );
3120     }
3121     ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
3122
3123     DestroyWindow( hwnd );
3124
3125     /* now test with a child window */
3126
3127     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
3128                               100, 100, 200, 200, 0, 0, 0, NULL);
3129     ok (hparent != 0, "Failed to create parent window\n");
3130
3131     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
3132                            10, 10, 100, 100, hparent, 0, 0, NULL);
3133     ok (hchild != 0, "Failed to create child window\n");
3134
3135     ShowWindow( hparent, SW_SHOW );
3136     UpdateWindow( hparent );
3137     UpdateWindow( hchild );
3138     /* try to flush pending X expose events */
3139     MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
3140     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3141
3142     flush_sequence();
3143     log_all_parent_messages++;
3144
3145     SetRect( &rect, 0, 0, 50, 50 );
3146     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
3147     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
3148     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
3149
3150     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
3151     pt.x = pt.y = 0;
3152     MapWindowPoints( hchild, hparent, &pt, 1 );
3153     SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
3154     check_update_rgn( hchild, hrgn );
3155     SetRectRgn( hrgn, 0, 0, 50, 50 );
3156     check_update_rgn( hparent, hrgn );
3157     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
3158     ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
3159     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
3160     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
3161
3162     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3163     ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
3164
3165     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
3166     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
3167     ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
3168     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
3169     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
3170
3171     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
3172     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
3173     ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
3174
3175     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
3176     flush_sequence();
3177     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
3178     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
3179     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
3180
3181     /* flush all paint messages */
3182     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3183     flush_sequence();
3184
3185     /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
3186     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
3187     SetRectRgn( hrgn, 0, 0, 50, 50 );
3188     check_update_rgn( hparent, hrgn );
3189     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
3190     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
3191     SetRectRgn( hrgn, 0, 0, 50, 50 );
3192     check_update_rgn( hparent, hrgn );
3193
3194     /* flush all paint messages */
3195     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3196     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
3197     flush_sequence();
3198
3199     /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
3200     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
3201     SetRectRgn( hrgn, 0, 0, 50, 50 );
3202     check_update_rgn( hparent, hrgn );
3203     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
3204     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
3205     SetRectRgn( hrgn2, 10, 10, 50, 50 );
3206     CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
3207     check_update_rgn( hparent, hrgn );
3208     /* flush all paint messages */
3209     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3210     flush_sequence();
3211
3212     /* same as above but parent gets completely validated */
3213     SetRect( &rect, 20, 20, 30, 30 );
3214     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
3215     SetRectRgn( hrgn, 20, 20, 30, 30 );
3216     check_update_rgn( hparent, hrgn );
3217     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
3218     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
3219     check_update_rgn( hparent, 0 );  /* no update region */
3220     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3221     ok_sequence( WmEmptySeq, "WmEmpty", FALSE );  /* and no paint messages */
3222
3223     /* make sure RDW_VALIDATE on child doesn't have the same effect */
3224     flush_sequence();
3225     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
3226     SetRectRgn( hrgn, 20, 20, 30, 30 );
3227     check_update_rgn( hparent, hrgn );
3228     RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
3229     SetRectRgn( hrgn, 20, 20, 30, 30 );
3230     check_update_rgn( hparent, hrgn );
3231
3232     /* same as above but normal WM_PAINT doesn't validate parent */
3233     flush_sequence();
3234     SetRect( &rect, 20, 20, 30, 30 );
3235     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
3236     SetRectRgn( hrgn, 20, 20, 30, 30 );
3237     check_update_rgn( hparent, hrgn );
3238     /* no WM_PAINT in child while parent still pending */
3239     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3240     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
3241     while (PeekMessage( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3242     ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
3243
3244     flush_sequence();
3245     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
3246     /* no WM_PAINT in child while parent still pending */
3247     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3248     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
3249     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
3250     /* now that parent is valid child should get WM_PAINT */
3251     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3252     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
3253     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3254     ok_sequence( WmEmptySeq, "No other message", FALSE );
3255
3256     /* same thing with WS_CLIPCHILDREN in parent */
3257     flush_sequence();
3258     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
3259     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
3260     /* changing style invalidates non client area, but we need to invalidate something else to see it */
3261     RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
3262     ok_sequence( WmEmptySeq, "No message", FALSE );
3263     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
3264     ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
3265
3266     flush_sequence();
3267     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
3268     SetRectRgn( hrgn, 20, 20, 30, 30 );
3269     check_update_rgn( hparent, hrgn );
3270     /* no WM_PAINT in child while parent still pending */
3271     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3272     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
3273     /* WM_PAINT in parent first */
3274     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3275     ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
3276
3277     /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
3278     flush_sequence();
3279     SetRect( &rect, 0, 0, 30, 30 );
3280     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
3281     SetRectRgn( hrgn, 0, 0, 30, 30 );
3282     check_update_rgn( hparent, hrgn );
3283     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3284     ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
3285
3286     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
3287     flush_sequence();
3288     SetRect( &rect, -10, 0, 30, 30 );
3289     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
3290     SetRect( &rect, 0, 0, 20, 20 );
3291     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
3292     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
3293     ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
3294
3295     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
3296     flush_sequence();
3297     SetRect( &rect, -10, 0, 30, 30 );
3298     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
3299     SetRect( &rect, 0, 0, 100, 100 );
3300     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
3301     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
3302     ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
3303     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
3304     ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
3305
3306     /* test RDW_INTERNALPAINT behavior */
3307
3308     flush_sequence();
3309     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
3310     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3311     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
3312
3313     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
3314     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3315     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
3316
3317     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
3318     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3319     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
3320
3321     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
3322     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
3323     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
3324     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3325     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
3326
3327     log_all_parent_messages--;
3328     DestroyWindow( hparent );
3329
3330     DeleteObject( hrgn );
3331     DeleteObject( hrgn2 );
3332 }
3333
3334 struct wnd_event
3335 {
3336     HWND hwnd;
3337     HANDLE event;
3338 };
3339
3340 static DWORD WINAPI thread_proc(void *param)
3341 {
3342     MSG msg;
3343     struct wnd_event *wnd_event = (struct wnd_event *)param;
3344
3345     wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
3346                                       100, 100, 200, 200, 0, 0, 0, NULL);
3347     ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
3348
3349     SetEvent(wnd_event->event);
3350
3351     while (GetMessage(&msg, 0, 0, 0))
3352     {
3353         TranslateMessage(&msg);
3354         DispatchMessage(&msg);
3355     }
3356
3357     return 0;
3358 }
3359
3360 static void test_interthread_messages(void)
3361 {
3362     HANDLE hThread;
3363     DWORD tid;
3364     WNDPROC proc;
3365     MSG msg;
3366     char buf[256];
3367     int len, expected_len;
3368     struct wnd_event wnd_event;
3369
3370     wnd_event.event = CreateEventW(NULL, 0, 0, NULL);
3371     if (!wnd_event.event)
3372     {
3373         trace("skipping interthread message test under win9x\n");
3374         return;
3375     }
3376
3377     hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
3378     ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError());
3379
3380     ok(WaitForSingleObject(wnd_event.event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
3381
3382     CloseHandle(wnd_event.event);
3383
3384     SetLastError(0xdeadbeef);
3385     ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeded\n");
3386     ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error code %ld\n", GetLastError());
3387
3388     proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
3389     ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %ld\n", GetLastError());
3390
3391     expected_len = lstrlenA("window caption text");
3392     memset(buf, 0, sizeof(buf));
3393     SetLastError(0xdeadbeef);
3394     len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
3395     ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %ld, len %d, expected len %d\n", GetLastError(), len, expected_len);
3396     ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
3397
3398     msg.hwnd = wnd_event.hwnd;
3399     msg.message = WM_GETTEXT;
3400     msg.wParam = sizeof(buf);
3401     msg.lParam = (LPARAM)buf;
3402     memset(buf, 0, sizeof(buf));
3403     SetLastError(0xdeadbeef);
3404     len = DispatchMessageA(&msg);
3405     ok(!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3406        "DispatchMessageA(WM_GETTEXT) succeded on another thread window: ret %d, error %ld\n", len, GetLastError());
3407
3408     /* the following test causes an exception in user.exe under win9x */
3409     msg.hwnd = wnd_event.hwnd;
3410     msg.message = WM_TIMER;
3411     msg.wParam = 0;
3412     msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
3413     SetLastError(0xdeadbeef);
3414     len = DispatchMessageA(&msg);
3415     ok(!len && GetLastError() == 0xdeadbeef,
3416        "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %ld\n", len, GetLastError());
3417
3418     ok(PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0), "PostMessageA(WM_QUIT) error %ld\n", GetLastError());
3419
3420     ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
3421     CloseHandle(hThread);
3422 }
3423
3424
3425 static const struct message WmVkN[] = {
3426     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
3427     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
3428     { WM_CHAR, wparam|lparam, 'n', 1 },
3429     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
3430     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
3431     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
3432     { 0 }
3433 };
3434 static const struct message WmShiftVkN[] = {
3435     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
3436     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
3437     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
3438     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
3439     { WM_CHAR, wparam|lparam, 'N', 1 },
3440     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
3441     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
3442     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
3443     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
3444     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
3445     { 0 }
3446 };
3447 static const struct message WmCtrlVkN[] = {
3448     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
3449     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
3450     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
3451     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
3452     { WM_CHAR, wparam|lparam, 0x000e, 1 },
3453     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
3454     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
3455     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
3456     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
3457     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
3458     { 0 }
3459 };
3460 static const struct message WmCtrlVkN_2[] = {
3461     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
3462     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
3463     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
3464     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
3465     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
3466     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
3467     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
3468     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
3469     { 0 }
3470 };
3471 static const struct message WmAltVkN[] = {
3472     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
3473     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
3474     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
3475     { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
3476     { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
3477     { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
3478     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
3479     { HCBT_SYSCOMMAND, hook },
3480     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
3481     { WM_SETCURSOR, sent|defwinproc },
3482     { WM_INITMENU, sent|defwinproc },
3483     { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
3484     { WM_CAPTURECHANGED, sent|defwinproc },
3485     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
3486     { WM_EXITMENULOOP, sent|defwinproc },
3487     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
3488     { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
3489     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
3490     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
3491     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
3492     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
3493     { 0 }
3494 };
3495 static const struct message WmAltVkN_2[] = {
3496     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
3497     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
3498     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
3499     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
3500     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
3501     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
3502     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
3503     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
3504     { 0 }
3505 };
3506 static const struct message WmCtrlAltVkN[] = {
3507     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
3508     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
3509     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
3510     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
3511     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
3512     { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
3513     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
3514     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
3515     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
3516     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
3517     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
3518     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
3519     { 0 }
3520 };
3521
3522 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
3523 {
3524     MSG msg;
3525
3526     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
3527     {
3528         struct message log_msg;
3529
3530         trace("accel: %p, %04x, %08x, %08lx\n", msg.hwnd, msg.message, msg.wParam, msg.lParam);
3531
3532         log_msg.message = msg.message;
3533         log_msg.flags = wparam|lparam;
3534         log_msg.wParam = msg.wParam;
3535         log_msg.lParam = msg.lParam;
3536         add_message(&log_msg);
3537
3538         if (!TranslateAccelerator(hwnd, hAccel, &msg))
3539         {
3540             TranslateMessage(&msg);
3541             DispatchMessage(&msg);
3542         }
3543     }
3544 }
3545
3546 static void test_accelerators(void)
3547 {
3548     SHORT state;
3549     HACCEL hAccel;
3550     HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
3551                                 100, 100, 200, 200, 0, 0, 0, NULL);
3552     assert(hwnd != 0);
3553
3554     SetFocus(hwnd);
3555     ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
3556
3557     state = GetKeyState(VK_SHIFT);
3558     ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
3559     state = GetKeyState(VK_CAPITAL);
3560     ok(state == 0, "wrong CapsLock state %04x\n", state);
3561
3562     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(1));
3563     assert(hAccel != 0);
3564
3565     trace("testing VK_N press/release\n");
3566     flush_sequence();
3567     keybd_event('N', 0, 0, 0);
3568     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3569     pump_msg_loop(hwnd, hAccel);
3570     ok_sequence(WmVkN, "VK_N press/release", FALSE);
3571
3572     trace("testing Shift+VK_N press/release\n");
3573     flush_sequence();
3574     keybd_event(VK_SHIFT, 0, 0, 0);
3575     keybd_event('N', 0, 0, 0);
3576     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3577     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
3578     pump_msg_loop(hwnd, hAccel);
3579     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
3580
3581     trace("testing Ctrl+VK_N press/release\n");
3582     flush_sequence();
3583     keybd_event(VK_CONTROL, 0, 0, 0);
3584     keybd_event('N', 0, 0, 0);
3585     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3586     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
3587     pump_msg_loop(hwnd, hAccel);
3588     ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
3589
3590     trace("testing Alt+VK_N press/release\n");
3591     flush_sequence();
3592     keybd_event(VK_MENU, 0, 0, 0);
3593     keybd_event('N', 0, 0, 0);
3594     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3595     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
3596     pump_msg_loop(hwnd, hAccel);
3597     ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
3598
3599     trace("testing Ctrl+Alt+VK_N press/release\n");
3600     flush_sequence();
3601     keybd_event(VK_CONTROL, 0, 0, 0);
3602     keybd_event(VK_MENU, 0, 0, 0);
3603     keybd_event('N', 0, 0, 0);
3604     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3605     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
3606     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
3607     pump_msg_loop(hwnd, hAccel);
3608     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
3609
3610     ok(DestroyAcceleratorTable(hAccel), "DestroyAcceleratorTable error %ld\n", GetLastError());
3611
3612     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(2));
3613     assert(hAccel != 0);
3614
3615     trace("testing VK_N press/release\n");
3616     flush_sequence();
3617     keybd_event('N', 0, 0, 0);
3618     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3619     pump_msg_loop(hwnd, hAccel);
3620     ok_sequence(WmVkN, "VK_N press/release", FALSE);
3621
3622     trace("testing Shift+VK_N press/release\n");
3623     flush_sequence();
3624     keybd_event(VK_SHIFT, 0, 0, 0);
3625     keybd_event('N', 0, 0, 0);
3626     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3627     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
3628     pump_msg_loop(hwnd, hAccel);
3629     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
3630
3631     trace("testing Ctrl+VK_N press/release 2\n");
3632     flush_sequence();
3633     keybd_event(VK_CONTROL, 0, 0, 0);
3634     keybd_event('N', 0, 0, 0);
3635     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3636     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
3637     pump_msg_loop(hwnd, hAccel);
3638     ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
3639
3640     trace("testing Alt+VK_N press/release 2\n");
3641     flush_sequence();
3642     keybd_event(VK_MENU, 0, 0, 0);
3643     keybd_event('N', 0, 0, 0);
3644     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3645     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
3646     pump_msg_loop(hwnd, hAccel);
3647     ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
3648
3649     trace("testing Ctrl+Alt+VK_N press/release\n");
3650     flush_sequence();
3651     keybd_event(VK_CONTROL, 0, 0, 0);
3652     keybd_event(VK_MENU, 0, 0, 0);
3653     keybd_event('N', 0, 0, 0);
3654     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
3655     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
3656     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
3657     pump_msg_loop(hwnd, hAccel);
3658     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
3659
3660     ok(DestroyAcceleratorTable(hAccel), "DestroyAcceleratorTable error %ld\n", GetLastError());
3661
3662     DestroyWindow(hwnd);
3663 }
3664
3665 /************* window procedures ********************/
3666
3667 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3668 {
3669     static long defwndproc_counter = 0;
3670     static long beginpaint_counter = 0;
3671     LRESULT ret;
3672     struct message msg;
3673
3674     trace("%p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
3675
3676     switch (message)
3677     {
3678         case WM_WINDOWPOSCHANGING:
3679         case WM_WINDOWPOSCHANGED:
3680         {
3681             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
3682
3683             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
3684             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
3685                   winpos->hwnd, winpos->hwndInsertAfter,
3686                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
3687
3688             /* Log only documented flags, win2k uses 0x1000 and 0x2000
3689              * in the high word for internal purposes
3690              */
3691             wParam = winpos->flags & 0xffff;
3692             break;
3693         }
3694     }
3695
3696     msg.message = message;
3697     msg.flags = sent|wparam|lparam;
3698     if (defwndproc_counter) msg.flags |= defwinproc;
3699     if (beginpaint_counter) msg.flags |= beginpaint;
3700     msg.wParam = wParam;
3701     msg.lParam = lParam;
3702     add_message(&msg);
3703
3704     if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
3705     {
3706         HWND parent = GetParent(hwnd);
3707         RECT rc;
3708         MINMAXINFO *minmax = (MINMAXINFO *)lParam;
3709
3710         GetClientRect(parent, &rc);
3711         trace("parent %p client size = (%ld x %ld)\n", parent, rc.right, rc.bottom);
3712
3713         trace("ptReserved = (%ld,%ld)\n"
3714               "ptMaxSize = (%ld,%ld)\n"
3715               "ptMaxPosition = (%ld,%ld)\n"
3716               "ptMinTrackSize = (%ld,%ld)\n"
3717               "ptMaxTrackSize = (%ld,%ld)\n",
3718               minmax->ptReserved.x, minmax->ptReserved.y,
3719               minmax->ptMaxSize.x, minmax->ptMaxSize.y,
3720               minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
3721               minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
3722               minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
3723
3724         ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %ld != %ld\n",
3725            minmax->ptMaxSize.x, rc.right);
3726         ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %ld != %ld\n",
3727            minmax->ptMaxSize.y, rc.bottom);
3728     }
3729
3730     if (message == WM_PAINT)
3731     {
3732         PAINTSTRUCT ps;
3733         beginpaint_counter++;
3734         BeginPaint( hwnd, &ps );
3735         beginpaint_counter--;
3736         EndPaint( hwnd, &ps );
3737         return 0;
3738     }
3739
3740     defwndproc_counter++;
3741     ret = DefWindowProcA(hwnd, message, wParam, lParam);
3742     defwndproc_counter--;
3743
3744     return ret;
3745 }
3746
3747 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3748 {
3749     static long defwndproc_counter = 0;
3750     LRESULT ret;
3751     struct message msg;
3752
3753     trace("popup: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
3754
3755     msg.message = message;
3756     msg.flags = sent|wparam|lparam;
3757     if (defwndproc_counter) msg.flags |= defwinproc;
3758     msg.wParam = wParam;
3759     msg.lParam = lParam;
3760     add_message(&msg);
3761
3762     if (message == WM_CREATE)
3763     {
3764         DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
3765         SetWindowLongA(hwnd, GWL_STYLE, style);
3766     }
3767
3768     defwndproc_counter++;
3769     ret = DefWindowProcA(hwnd, message, wParam, lParam);
3770     defwndproc_counter--;
3771
3772     return ret;
3773 }
3774
3775 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3776 {
3777     static long defwndproc_counter = 0;
3778     static long beginpaint_counter = 0;
3779     LRESULT ret;
3780     struct message msg;
3781
3782     trace("parent: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
3783
3784     if (log_all_parent_messages ||
3785         message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
3786         message == WM_SETFOCUS || message == WM_KILLFOCUS ||
3787         message == WM_ENABLE || message == WM_ENTERIDLE ||
3788         message == WM_IME_SETCONTEXT)
3789     {
3790         msg.message = message;
3791         msg.flags = sent|parent|wparam|lparam;
3792         if (defwndproc_counter) msg.flags |= defwinproc;
3793         if (beginpaint_counter) msg.flags |= beginpaint;
3794         msg.wParam = wParam;
3795         msg.lParam = lParam;
3796         add_message(&msg);
3797     }
3798
3799     if (message == WM_PAINT)
3800     {
3801         PAINTSTRUCT ps;
3802         beginpaint_counter++;
3803         BeginPaint( hwnd, &ps );
3804         beginpaint_counter--;
3805         EndPaint( hwnd, &ps );
3806         return 0;
3807     }
3808
3809     defwndproc_counter++;
3810     ret = DefWindowProcA(hwnd, message, wParam, lParam);
3811     defwndproc_counter--;
3812
3813     return ret;
3814 }
3815
3816 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3817 {
3818     static long defwndproc_counter = 0;
3819     LRESULT ret;
3820     struct message msg;
3821
3822     trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
3823
3824     DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
3825     ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
3826     if (after_end_dialog)
3827         ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
3828     else
3829         ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
3830
3831     msg.message = message;
3832     msg.flags = sent|wparam|lparam;
3833     if (defwndproc_counter) msg.flags |= defwinproc;
3834     msg.wParam = wParam;
3835     msg.lParam = lParam;
3836     add_message(&msg);
3837
3838     defwndproc_counter++;
3839     ret = DefDlgProcA(hwnd, message, wParam, lParam);
3840     defwndproc_counter--;
3841
3842     return ret;
3843 }
3844
3845 static BOOL RegisterWindowClasses(void)
3846 {
3847     WNDCLASSA cls;
3848
3849     cls.style = 0;
3850     cls.lpfnWndProc = MsgCheckProcA;
3851     cls.cbClsExtra = 0;
3852     cls.cbWndExtra = 0;
3853     cls.hInstance = GetModuleHandleA(0);
3854     cls.hIcon = 0;
3855     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
3856     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
3857     cls.lpszMenuName = NULL;
3858     cls.lpszClassName = "TestWindowClass";
3859     if(!RegisterClassA(&cls)) return FALSE;
3860
3861     cls.lpfnWndProc = PopupMsgCheckProcA;
3862     cls.lpszClassName = "TestPopupClass";
3863     if(!RegisterClassA(&cls)) return FALSE;
3864
3865     cls.lpfnWndProc = ParentMsgCheckProcA;
3866     cls.lpszClassName = "TestParentClass";
3867     if(!RegisterClassA(&cls)) return FALSE;
3868
3869     cls.lpfnWndProc = DefWindowProcA;
3870     cls.lpszClassName = "SimpleWindowClass";
3871     if(!RegisterClassA(&cls)) return FALSE;
3872
3873     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
3874     cls.lpfnWndProc = TestDlgProcA;
3875     cls.lpszClassName = "TestDialogClass";
3876     if(!RegisterClassA(&cls)) return FALSE;
3877
3878     return TRUE;
3879 }
3880
3881 static HHOOK hCBT_hook;
3882
3883 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
3884
3885     char buf[256];
3886
3887     trace("CBT: %d, %08x, %08lx\n", nCode, wParam, lParam);
3888
3889     if (nCode == HCBT_SYSCOMMAND)
3890     {
3891         struct message msg;
3892
3893         msg.message = nCode;
3894         msg.flags = hook;
3895         msg.wParam = wParam;
3896         msg.lParam = lParam;
3897         add_message(&msg);
3898
3899         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
3900     }
3901
3902     /* Log also SetFocus(0) calls */
3903     if (!wParam) wParam = lParam;
3904
3905     if (GetClassNameA((HWND)wParam, buf, sizeof(buf)))
3906     {
3907         if (!strcmp(buf, "TestWindowClass") ||
3908             !strcmp(buf, "TestParentClass") ||
3909             !strcmp(buf, "TestPopupClass") ||
3910             !strcmp(buf, "SimpleWindowClass") ||
3911             !strcmp(buf, "TestDialogClass") ||
3912             !strcmp(buf, "MDI_frame_class") ||
3913             !strcmp(buf, "MDI_client_class") ||
3914             !strcmp(buf, "MDI_child_class") ||
3915             !strcmp(buf, "my_button_class") ||
3916             !strcmp(buf, "#32770"))
3917         {
3918             struct message msg;
3919
3920             msg.message = nCode;
3921             msg.flags = hook;
3922             msg.wParam = wParam;
3923             msg.lParam = lParam;
3924             add_message(&msg);
3925         }
3926     }
3927     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
3928 }
3929
3930 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
3931 static const WCHAR wszAnsi[] = {'U',0};
3932
3933 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
3934 {
3935     switch (uMsg)
3936     {
3937     case CB_FINDSTRINGEXACT:
3938         trace("String: %p\n", (LPCWSTR)lParam);
3939         if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
3940             return 1;
3941         if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
3942             return 0;
3943         return -1;
3944     }
3945     return DefWindowProcW(hwnd, uMsg, wParam, lParam);
3946 }
3947
3948 static void test_message_conversion(void)
3949 {
3950     static const WCHAR wszMsgConversionClass[] =
3951         {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
3952     WNDCLASSW cls;
3953     LRESULT lRes;
3954     HWND hwnd;
3955     WNDPROC wndproc;
3956
3957     cls.style = 0;
3958     cls.lpfnWndProc = MsgConversionProcW;
3959     cls.cbClsExtra = 0;
3960     cls.cbWndExtra = 0;
3961     cls.hInstance = GetModuleHandleW(NULL);
3962     cls.hIcon = NULL;
3963     cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
3964     cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
3965     cls.lpszMenuName = NULL;
3966     cls.lpszClassName = wszMsgConversionClass;
3967     /* this call will fail on Win9x, but that doesn't matter as this test is
3968      * meaningless on those platforms */
3969     if(!RegisterClassW(&cls)) return;
3970
3971     hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
3972                            100, 100, 200, 200, 0, 0, 0, NULL);
3973     ok(hwnd != NULL, "Window creation failed\n");
3974
3975     /* {W, A} -> A */
3976
3977     wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
3978     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3979     ok(lRes == 0, "String should have been converted\n");
3980     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3981     ok(lRes == 1, "String shouldn't have been converted\n");
3982
3983     /* {W, A} -> W */
3984
3985     wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
3986     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3987     ok(lRes == 1, "String shouldn't have been converted\n");
3988     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3989     ok(lRes == 1, "String shouldn't have been converted\n");
3990
3991     /* Synchronous messages */
3992
3993     lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3994     ok(lRes == 0, "String should have been converted\n");
3995     lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
3996     ok(lRes == 1, "String shouldn't have been converted\n");
3997
3998     /* Asynchronous messages */
3999
4000     SetLastError(0);
4001     lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4002     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4003         "PostMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4004     SetLastError(0);
4005     lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4006     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4007         "PostMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4008     SetLastError(0);
4009     lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4010     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4011         "PosThreadtMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4012     SetLastError(0);
4013     lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4014     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4015         "PosThreadtMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4016     SetLastError(0);
4017     lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4018     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4019         "SendNotifyMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4020     SetLastError(0);
4021     lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4022     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4023         "SendNotifyMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4024     SetLastError(0);
4025     lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
4026     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4027         "SendMessageCallback on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4028     SetLastError(0);
4029     lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
4030     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4031         "SendMessageCallback on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4032 }
4033
4034 typedef struct _thread_info
4035 {
4036     HWND hWnd;
4037     HANDLE handles[2];
4038     DWORD id;
4039 } thread_info;
4040
4041 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT id, DWORD dwTime)
4042 {
4043 }
4044
4045 #define TIMER_ID  0x19
4046
4047 static DWORD WINAPI timer_thread_proc(LPVOID x)
4048 {
4049     thread_info *info = x;
4050     DWORD r;
4051
4052     r = KillTimer(info->hWnd, 0x19);
4053     ok(r,"KillTimer failed in thread\n");
4054     r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
4055     ok(r,"SetTimer failed in thread\n");
4056     ok(r==TIMER_ID,"SetTimer id different\n");
4057     r = SetEvent(info->handles[0]);
4058     ok(r,"SetEvent failed in thread\n");
4059     return 0;
4060 }
4061
4062 static void test_timers(void)
4063 {
4064     thread_info info;
4065     DWORD id;
4066
4067     info.hWnd = CreateWindow ("TestWindowClass", NULL,
4068        WS_OVERLAPPEDWINDOW ,
4069        CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4070        NULL, NULL, 0);
4071
4072     info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
4073     ok(info.id, "SetTimer failed\n");
4074     ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
4075     info.handles[0] = CreateEvent(NULL,0,0,NULL);
4076     info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
4077
4078     WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
4079
4080     WaitForSingleObject(info.handles[1], INFINITE);
4081
4082     ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
4083
4084     ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
4085 }
4086
4087 START_TEST(msg)
4088 {
4089     if (!RegisterWindowClasses()) assert(0);
4090
4091     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
4092     assert(hCBT_hook);
4093
4094     test_messages();
4095     test_mdi_messages();
4096     test_button_messages();
4097     test_paint_messages();
4098     test_interthread_messages();
4099     test_message_conversion();
4100     test_accelerators();
4101     test_timers();
4102
4103     UnhookWindowsHookEx(hCBT_hook);
4104 }