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