Added a couple of SetWindowPos tests.
[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, 2005 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 static HWINEVENTHOOK hEvent_hook;
43
44 /*
45 FIXME: add tests for these
46 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
47  WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
48  WS_THICKFRAME: thick border
49  WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
50  WS_BORDER (default for overlapped windows): single black border
51  none (default for child (and popup?) windows): no border
52 */
53
54 typedef enum {
55     sent=0x1,
56     posted=0x2,
57     parent=0x4,
58     wparam=0x8,
59     lparam=0x10,
60     defwinproc=0x20,
61     beginpaint=0x40,
62     optional=0x80,
63     hook=0x100,
64     winevent_hook=0x200
65 } msg_flags_t;
66
67 struct message {
68     UINT message;          /* the WM_* code */
69     msg_flags_t flags;     /* message props */
70     WPARAM wParam;         /* expected value of wParam */
71     LPARAM lParam;         /* expected value of lParam */
72 };
73
74 /* Empty message sequence */
75 static const struct message WmEmptySeq[] =
76 {
77     { 0 }
78 };
79 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
80 static const struct message WmCreateOverlappedSeq[] = {
81     { HCBT_CREATEWND, hook },
82     { WM_GETMINMAXINFO, sent },
83     { WM_NCCREATE, sent },
84     { WM_NCCALCSIZE, sent|wparam, 0 },
85     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
86     { WM_CREATE, sent },
87     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
88     { 0 }
89 };
90 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
91  * for a not visible overlapped window.
92  */
93 static const struct message WmSWP_ShowOverlappedSeq[] = {
94     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
95     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
96     { WM_NCPAINT, sent|wparam|optional, 1 },
97     { WM_GETTEXT, sent|defwinproc|optional },
98     { WM_ERASEBKGND, sent|optional },
99     { HCBT_ACTIVATE, hook },
100     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
101     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
102     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
103     { WM_ACTIVATEAPP, sent|wparam, 1 },
104     { WM_NCACTIVATE, sent|wparam, 1 },
105     { WM_GETTEXT, sent|defwinproc|optional },
106     { WM_ACTIVATE, sent|wparam, 1 },
107     { HCBT_SETFOCUS, hook },
108     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
109     { WM_IME_NOTIFY, sent|defwinproc|optional },
110     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
111     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
112     { WM_NCPAINT, sent|wparam|optional, 1 },
113     { WM_GETTEXT, sent|defwinproc|optional },
114     { WM_ERASEBKGND, sent|optional },
115     /* Win9x adds SWP_NOZORDER below */
116     { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
117     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
118     { WM_NCPAINT, sent|wparam|optional, 1 },
119     { WM_ERASEBKGND, sent|optional },
120     { 0 }
121 };
122 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
123  * for a visible overlapped window.
124  */
125 static const struct message WmSWP_HideOverlappedSeq[] = {
126     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
127     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
128     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
129     { 0 }
130 };
131
132 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
133  * for a visible overlapped window.
134  */
135 static const struct message WmSWP_ResizeSeq[] = {
136     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOMOVE },
137     { WM_GETMINMAXINFO, sent|defwinproc },
138     { WM_NCCALCSIZE, sent|wparam, TRUE },
139     { WM_NCPAINT, sent|optional },
140     { WM_GETTEXT, sent|defwinproc|optional },
141     { WM_ERASEBKGND, sent|optional },
142     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
143     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
144     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
145     { WM_NCPAINT, sent|optional },
146     { WM_GETTEXT, sent|defwinproc|optional },
147     { WM_ERASEBKGND, sent|optional },
148     { 0 }
149 };
150
151 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
152  * for a visible popup window.
153  */
154 static const struct message WmSWP_ResizePopupSeq[] = {
155     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOMOVE },
156     { WM_NCCALCSIZE, sent|wparam, TRUE },
157     { WM_NCPAINT, sent|optional },
158     { WM_GETTEXT, sent|defwinproc|optional },
159     { WM_ERASEBKGND, sent|optional },
160     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
161     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
162     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
163     { WM_NCPAINT, sent|optional },
164     { WM_GETTEXT, sent|defwinproc|optional },
165     { WM_ERASEBKGND, sent|optional },
166     { 0 }
167 };
168
169 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE)
170  * for a visible overlapped window.
171  */
172 static const struct message WmSWP_MoveSeq[] = {
173     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE },
174     { WM_NCPAINT, sent|optional },
175     { WM_GETTEXT, sent|defwinproc|optional },
176     { WM_ERASEBKGND, sent|optional },
177     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOCLIENTSIZE },
178     { WM_MOVE, sent|defwinproc|wparam, 0 },
179     { 0 }
180 };
181
182 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
183 static const struct message WmShowOverlappedSeq[] = {
184     { WM_SHOWWINDOW, sent|wparam, 1 },
185     { WM_NCPAINT, sent|wparam|optional, 1 },
186     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
187     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
188     { WM_NCPAINT, sent|wparam|optional, 1 },
189     { WM_GETTEXT, sent|defwinproc|optional },
190     { WM_ERASEBKGND, sent|optional },
191     { HCBT_ACTIVATE, hook },
192     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
193     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
194     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
195     { WM_ACTIVATEAPP, sent|wparam, 1 },
196     { WM_NCACTIVATE, sent|wparam, 1 },
197     { WM_GETTEXT, sent|defwinproc|optional },
198     { WM_ACTIVATE, sent|wparam, 1 },
199     { HCBT_SETFOCUS, hook },
200     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
201     { WM_IME_NOTIFY, sent|defwinproc|optional },
202     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
203     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
204     { WM_NCPAINT, sent|wparam|optional, 1 },
205     { WM_GETTEXT, sent|defwinproc|optional },
206     { WM_ERASEBKGND, sent|optional },
207     /* Win9x adds SWP_NOZORDER below */
208     { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
209     { WM_NCCALCSIZE, sent|optional },
210     { WM_NCPAINT, sent|optional },
211     { WM_ERASEBKGND, sent|optional },
212 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
213        * messages. Does that mean that CreateWindow doesn't set initial
214        * window dimensions for overlapped windows?
215        */
216     { WM_SIZE, sent },
217     { WM_MOVE, sent },
218 #endif
219     { 0 }
220 };
221 /* ShowWindow(SW_HIDE) for a visible overlapped window */
222 static const struct message WmHideOverlappedSeq[] = {
223     { WM_SHOWWINDOW, sent|wparam, 0 },
224     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
225     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
226     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
227     { WM_SIZE, sent },
228     { WM_MOVE, sent },
229     { WM_NCACTIVATE, sent|wparam, 0 },
230     { WM_ACTIVATE, sent|wparam, 0 },
231     { WM_ACTIVATEAPP, sent|wparam, 0 },
232     { WM_KILLFOCUS, sent|wparam, 0 },
233     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
234     { WM_IME_NOTIFY, sent|optional|defwinproc },
235     { 0 }
236 };
237 /* ShowWindow(SW_HIDE) for an invisible overlapped window */
238 static const struct message WmHideInvisibleOverlappedSeq[] = {
239     { 0 }
240 };
241 /* DestroyWindow for a visible overlapped window */
242 static const struct message WmDestroyOverlappedSeq[] = {
243     { HCBT_DESTROYWND, hook },
244     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
245     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
246     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
247     { WM_NCACTIVATE, sent|wparam, 0 },
248     { WM_ACTIVATE, sent|wparam, 0 },
249     { WM_ACTIVATEAPP, sent|wparam, 0 },
250     { WM_KILLFOCUS, sent|wparam, 0 },
251     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
252     { WM_IME_NOTIFY, sent|optional|defwinproc },
253     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
254     { WM_DESTROY, sent },
255     { WM_NCDESTROY, sent },
256     { 0 }
257 };
258 /* CreateWindow (for a child popup window, not initially visible) */
259 static const struct message WmCreateChildPopupSeq[] = {
260     { HCBT_CREATEWND, hook },
261     { WM_NCCREATE, sent }, 
262     { WM_NCCALCSIZE, sent|wparam, 0 },
263     { WM_CREATE, sent },
264     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
265     { WM_SIZE, sent },
266     { WM_MOVE, sent },
267     { 0 }
268 };
269 /* CreateWindow (for a popup window, not initially visible,
270  * which sets WS_VISIBLE in WM_CREATE handler)
271  */
272 static const struct message WmCreateInvisiblePopupSeq[] = {
273     { HCBT_CREATEWND, hook },
274     { WM_NCCREATE, sent }, 
275     { WM_NCCALCSIZE, sent|wparam, 0 },
276     { WM_CREATE, sent },
277     { WM_STYLECHANGING, sent },
278     { WM_STYLECHANGED, sent },
279     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
280     { WM_SIZE, sent },
281     { WM_MOVE, sent },
282     { 0 }
283 };
284 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
285  * for a popup window with WS_VISIBLE style set
286  */
287 static const struct message WmShowVisiblePopupSeq_2[] = {
288     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
289     { 0 }
290 };
291 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
292  * for a popup window with WS_VISIBLE style set
293  */
294 static const struct message WmShowVisiblePopupSeq_3[] = {
295     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
296     { HCBT_ACTIVATE, hook },
297     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
298     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
299     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
300     { WM_NCACTIVATE, sent|wparam, 1 },
301     { WM_ACTIVATE, sent|wparam, 1 },
302     { HCBT_SETFOCUS, hook },
303     { WM_KILLFOCUS, sent|parent },
304     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
305     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
306     { WM_IME_NOTIFY, sent|defwinproc|optional },
307     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
308     { WM_SETFOCUS, sent|defwinproc },
309     { 0 }
310 };
311 /* CreateWindow (for child window, not initially visible) */
312 static const struct message WmCreateChildSeq[] = {
313     { HCBT_CREATEWND, hook },
314     { WM_NCCREATE, sent }, 
315     /* child is inserted into parent's child list after WM_NCCREATE returns */
316     { WM_NCCALCSIZE, sent|wparam, 0 },
317     { WM_CREATE, sent },
318     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
319     { WM_SIZE, sent },
320     { WM_MOVE, sent },
321     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
322     { 0 }
323 };
324 /* CreateWindow (for maximized child window, not initially visible) */
325 static const struct message WmCreateMaximizedChildSeq[] = {
326     { HCBT_CREATEWND, hook },
327     { WM_NCCREATE, sent }, 
328     { WM_NCCALCSIZE, sent|wparam, 0 },
329     { WM_CREATE, sent },
330     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
331     { WM_SIZE, sent },
332     { WM_MOVE, sent },
333     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
334     { WM_GETMINMAXINFO, sent },
335     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
336     { WM_NCCALCSIZE, sent|wparam, 1 },
337     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTMOVE|0x8000 },
338     { WM_SIZE, sent|defwinproc },
339     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
340     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
341     { 0 }
342 };
343 /* CreateWindow (for a child window, initially visible) */
344 static const struct message WmCreateVisibleChildSeq[] = {
345     { HCBT_CREATEWND, hook },
346     { WM_NCCREATE, sent }, 
347     /* child is inserted into parent's child list after WM_NCCREATE returns */
348     { WM_NCCALCSIZE, sent|wparam, 0 },
349     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
350     { WM_CREATE, sent },
351     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
352     { WM_SIZE, sent },
353     { WM_MOVE, sent },
354     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
355     { WM_SHOWWINDOW, sent|wparam, 1 },
356     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER },
357     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
358     { WM_ERASEBKGND, sent|parent|optional },
359     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
360     { 0 }
361 };
362 /* ShowWindow(SW_SHOW) for a not visible child window */
363 static const struct message WmShowChildSeq[] = {
364     { WM_SHOWWINDOW, sent|wparam, 1 },
365     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
366     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
367     { WM_ERASEBKGND, sent|parent|optional },
368     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
369     { 0 }
370 };
371 /* ShowWindow(SW_HIDE) for a visible child window */
372 static const struct message WmHideChildSeq[] = {
373     { WM_SHOWWINDOW, sent|wparam, 0 },
374     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
375     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
376     { WM_ERASEBKGND, sent|parent|optional },
377     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
378     { 0 }
379 };
380 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
381  * for a not visible child window
382  */
383 static const struct message WmShowChildSeq_2[] = {
384     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
385     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
386     { WM_CHILDACTIVATE, sent },
387     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
388     { 0 }
389 };
390 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
391  * for a not visible child window
392  */
393 static const struct message WmShowChildSeq_3[] = {
394     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
395     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
396     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
397     { 0 }
398 };
399 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
400  * for a visible child window with a caption
401  */
402 static const struct message WmShowChildSeq_4[] = {
403     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
404     { WM_CHILDACTIVATE, sent },
405     { 0 }
406 };
407 /* ShowWindow(SW_SHOW) for child with invisible parent */
408 static const struct message WmShowChildInvisibleParentSeq[] = {
409     { WM_SHOWWINDOW, sent|wparam, 1 },
410     { 0 }
411 };
412 /* ShowWindow(SW_HIDE) for child with invisible parent */
413 static const struct message WmHideChildInvisibleParentSeq[] = {
414     { WM_SHOWWINDOW, sent|wparam, 0 },
415     { 0 }
416 };
417 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
418 static const struct message WmShowChildInvisibleParentSeq_2[] = {
419     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER },
420     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
421     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
422     { 0 }
423 };
424 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
425 static const struct message WmHideChildInvisibleParentSeq_2[] = {
426     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
427     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
428     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
429     { 0 }
430 };
431 /* DestroyWindow for a visible child window */
432 static const struct message WmDestroyChildSeq[] = {
433     { HCBT_DESTROYWND, hook },
434     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
435     { WM_SHOWWINDOW, sent|wparam, 0 },
436     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
437     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
438     { WM_ERASEBKGND, sent|parent|optional },
439     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
440     { HCBT_SETFOCUS, hook }, /* set focus to a parent */
441     { WM_KILLFOCUS, sent },
442     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
443     { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
444     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
445     { WM_SETFOCUS, sent|parent },
446     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
447     { WM_DESTROY, sent },
448     { WM_DESTROY, sent|optional }, /* some other (IME?) window */
449     { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
450     { WM_NCDESTROY, sent },
451     { 0 }
452 };
453 /* Moving the mouse in nonclient area */
454 static const struct message WmMouseMoveInNonClientAreaSeq[] = { /* FIXME: add */
455     { WM_NCHITTEST, sent },
456     { WM_SETCURSOR, sent },
457     { WM_NCMOUSEMOVE, posted },
458     { 0 }
459 };
460 /* Moving the mouse in client area */
461 static const struct message WmMouseMoveInClientAreaSeq[] = { /* FIXME: add */
462     { WM_NCHITTEST, sent },
463     { WM_SETCURSOR, sent },
464     { WM_MOUSEMOVE, posted },
465     { 0 }
466 };
467 /* Moving by dragging the title bar (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
468 static const struct message WmDragTitleBarSeq[] = { /* FIXME: add */
469     { WM_NCLBUTTONDOWN, sent|wparam, HTCAPTION },
470     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_MOVE+2 },
471     { WM_GETMINMAXINFO, sent|defwinproc },
472     { WM_ENTERSIZEMOVE, sent|defwinproc },
473     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
474     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
475     { WM_MOVE, sent|defwinproc },
476     { WM_EXITSIZEMOVE, sent|defwinproc },
477     { 0 }
478 };
479 /* Sizing by dragging the thick borders (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
480 static const struct message WmDragThickBordersBarSeq[] = { /* FIXME: add */
481     { WM_NCLBUTTONDOWN, sent|wparam, 0xd },
482     { WM_SYSCOMMAND, sent|defwinproc|wparam, 0xf004 },
483     { WM_GETMINMAXINFO, sent|defwinproc },
484     { WM_ENTERSIZEMOVE, sent|defwinproc },
485     { WM_SIZING, sent|defwinproc|wparam, 4}, /* one for each mouse movement */
486     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
487     { WM_GETMINMAXINFO, sent|defwinproc },
488     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
489     { WM_NCPAINT, sent|defwinproc|wparam, 1 },
490     { WM_GETTEXT, sent|defwinproc },
491     { WM_ERASEBKGND, sent|defwinproc },
492     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
493     { WM_MOVE, sent|defwinproc },
494     { WM_SIZE, sent|defwinproc },
495     { WM_EXITSIZEMOVE, sent|defwinproc },
496     { 0 }
497 };
498 /* Resizing child window with MoveWindow (32) */
499 static const struct message WmResizingChildWithMoveWindowSeq[] = {
500     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
501     { WM_NCCALCSIZE, sent|wparam, 1 },
502     { WM_ERASEBKGND, sent|optional },
503     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
504     { WM_MOVE, sent|defwinproc },
505     { WM_SIZE, sent|defwinproc },
506     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
507     { 0 }
508 };
509 /* Clicking on inactive button */
510 static const struct message WmClickInactiveButtonSeq[] = { /* FIXME: add */
511     { WM_NCHITTEST, sent },
512     { WM_PARENTNOTIFY, sent|parent|wparam, WM_LBUTTONDOWN },
513     { WM_MOUSEACTIVATE, sent },
514     { WM_MOUSEACTIVATE, sent|parent|defwinproc },
515     { WM_SETCURSOR, sent },
516     { WM_SETCURSOR, sent|parent|defwinproc },
517     { WM_LBUTTONDOWN, posted },
518     { WM_KILLFOCUS, posted|parent },
519     { WM_SETFOCUS, posted },
520     { WM_CTLCOLORBTN, posted|parent },
521     { BM_SETSTATE, posted },
522     { WM_CTLCOLORBTN, posted|parent },
523     { WM_LBUTTONUP, posted },
524     { BM_SETSTATE, posted },
525     { WM_CTLCOLORBTN, posted|parent },
526     { WM_COMMAND, posted|parent },
527     { 0 }
528 };
529 /* Reparenting a button (16/32) */
530 /* The last child (button) reparented gets topmost for its new parent. */
531 static const struct message WmReparentButtonSeq[] = { /* FIXME: add */
532     { WM_SHOWWINDOW, sent|wparam, 0 },
533     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER },
534     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
535     { WM_ERASEBKGND, sent|parent },
536     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER },
537     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOZORDER },
538     { WM_CHILDACTIVATE, sent },
539     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW|SWP_NOZORDER },
540     { WM_MOVE, sent|defwinproc },
541     { WM_SHOWWINDOW, sent|wparam, 1 },
542     { 0 }
543 };
544 /* Creation of a custom dialog (32) */
545 static const struct message WmCreateCustomDialogSeq[] = {
546     { HCBT_CREATEWND, hook },
547     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
548     { WM_GETMINMAXINFO, sent },
549     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
550     { WM_NCCREATE, sent },
551     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
552     { WM_NCCALCSIZE, sent|wparam, 0 },
553     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
554     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
555     { WM_CREATE, sent },
556     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
557     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
558     { WM_SHOWWINDOW, sent|wparam, 1 },
559     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
560     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
561     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
562     { HCBT_ACTIVATE, hook },
563     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
564
565     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
566
567     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
568     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
569
570     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
571
572     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
573     { WM_NCACTIVATE, sent|wparam, 1 },
574     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
575     { WM_GETTEXT, sent|optional|defwinproc },
576     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
577     { WM_GETICON, sent|optional|defwinproc },
578     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
579     { WM_GETICON, sent|optional|defwinproc },
580     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
581     { WM_GETICON, sent|optional|defwinproc },
582     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
583     { WM_GETTEXT, sent|optional|defwinproc },
584     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
585     { WM_ACTIVATE, sent|wparam, 1 },
586     { WM_KILLFOCUS, sent|parent },
587     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
588     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
589     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
590     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
591     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
592     { WM_IME_NOTIFY, sent|optional|defwinproc },
593     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
594     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
595     { WM_SETFOCUS, sent },
596     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
597     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
598     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
599     { WM_NCPAINT, sent|wparam, 1 },
600     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
601     { WM_GETTEXT, sent|optional|defwinproc },
602     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
603     { WM_GETICON, sent|optional|defwinproc },
604     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
605     { WM_GETICON, sent|optional|defwinproc },
606     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
607     { WM_GETICON, sent|optional|defwinproc },
608     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
609     { WM_GETTEXT, sent|optional|defwinproc },
610     { WM_ERASEBKGND, sent },
611     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
612     { WM_CTLCOLORDLG, sent|defwinproc },
613     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
614     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
615     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
616     { WM_GETTEXT, sent|optional },
617     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
618     { WM_GETICON, sent|optional },
619     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
620     { WM_GETICON, sent|optional },
621     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
622     { WM_GETICON, sent|optional },
623     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
624     { WM_GETTEXT, sent|optional },
625     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
626     { WM_NCCALCSIZE, sent|optional },
627     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
628     { WM_NCPAINT, sent|optional },
629     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
630     { WM_GETTEXT, sent|optional|defwinproc },
631     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
632     { WM_GETICON, sent|optional|defwinproc },
633     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
634     { WM_GETICON, sent|optional|defwinproc },
635     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
636     { WM_GETICON, sent|optional|defwinproc },
637     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
638     { WM_GETTEXT, sent|optional|defwinproc },
639     { WM_ERASEBKGND, sent|optional },
640     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
641     { WM_CTLCOLORDLG, sent|optional|defwinproc },
642     { WM_SIZE, sent },
643     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
644     { WM_MOVE, sent },
645     { 0 }
646 };
647 /* Calling EndDialog for a custom dialog (32) */
648 static const struct message WmEndCustomDialogSeq[] = {
649     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
650     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
651     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
652     { WM_GETTEXT, sent|optional },
653     { WM_GETICON, sent|optional },
654     { WM_GETICON, sent|optional },
655     { WM_GETICON, sent|optional },
656     { HCBT_ACTIVATE, hook },
657     { WM_NCACTIVATE, sent|wparam, 0 },
658     { WM_GETTEXT, sent|optional|defwinproc },
659     { WM_GETICON, sent|optional|defwinproc },
660     { WM_GETICON, sent|optional|defwinproc },
661     { WM_GETICON, sent|optional|defwinproc },
662     { WM_GETTEXT, sent|optional|defwinproc },
663     { WM_ACTIVATE, sent|wparam, 0 },
664     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
665     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
666     { HCBT_SETFOCUS, hook },
667     { WM_KILLFOCUS, sent },
668     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
669     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
670     { WM_IME_NOTIFY, sent|optional },
671     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
672     { WM_SETFOCUS, sent|parent|defwinproc },
673     { 0 }
674 };
675 /* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
676 static const struct message WmShowCustomDialogSeq[] = {
677     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
678     { WM_SHOWWINDOW, sent|wparam, 1 },
679     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
680     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
681     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
682     { HCBT_ACTIVATE, hook },
683     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
684
685     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
686     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
687
688     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
689     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
690     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
691     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
692     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
693     { WM_NCACTIVATE, sent|wparam, 1 },
694     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
695     { WM_ACTIVATE, sent|wparam, 1 },
696
697     { WM_KILLFOCUS, sent|parent },
698     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
699     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
700     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
701     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
702     { WM_IME_NOTIFY, sent|optional|defwinproc },
703     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
704     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
705     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
706     { WM_SETFOCUS, sent },
707     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
708     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
709     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
710     { WM_NCPAINT, sent|wparam, 1 },
711     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
712     { WM_ERASEBKGND, sent },
713     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
714     { WM_CTLCOLORDLG, sent|defwinproc },
715
716     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
717     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
718     { 0 }
719 };
720 /* Creation and destruction of a modal dialog (32) */
721 static const struct message WmModalDialogSeq[] = {
722     { WM_CANCELMODE, sent|parent },
723     { HCBT_SETFOCUS, hook },
724     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
725     { WM_KILLFOCUS, sent|parent },
726     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
727     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
728     { WM_ENABLE, sent|parent|wparam, 0 },
729     { HCBT_CREATEWND, hook },
730     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
731     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
732     { WM_SETFONT, sent },
733     { WM_INITDIALOG, sent },
734     { WM_CHANGEUISTATE, sent|optional },
735     { WM_SHOWWINDOW, sent },
736     { HCBT_ACTIVATE, hook },
737     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
738     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
739     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
740     { WM_NCACTIVATE, sent|wparam, 1 },
741     { WM_GETICON, sent|optional },
742     { WM_GETICON, sent|optional },
743     { WM_GETICON, sent|optional },
744     { WM_GETTEXT, sent|optional },
745     { WM_ACTIVATE, sent|wparam, 1 },
746     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE },
747     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
748     { WM_NCPAINT, sent },
749     { WM_GETICON, sent|optional },
750     { WM_GETICON, sent|optional },
751     { WM_GETICON, sent|optional },
752     { WM_GETTEXT, sent|optional },
753     { WM_ERASEBKGND, sent },
754     { WM_CTLCOLORDLG, sent },
755     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
756     { WM_GETICON, sent|optional },
757     { WM_GETICON, sent|optional },
758     { WM_GETICON, sent|optional },
759     { WM_GETTEXT, sent|optional },
760     { WM_NCCALCSIZE, sent|optional },
761     { WM_NCPAINT, sent|optional },
762     { WM_GETICON, sent|optional },
763     { WM_GETICON, sent|optional },
764     { WM_GETICON, sent|optional },
765     { WM_GETTEXT, sent|optional },
766     { WM_ERASEBKGND, sent|optional },
767     { WM_CTLCOLORDLG, sent|optional },
768     { WM_PAINT, sent|optional },
769     { WM_CTLCOLORBTN, sent },
770     { WM_ENTERIDLE, sent|parent|optional },
771     { WM_TIMER, sent },
772     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
773     { WM_ENABLE, sent|parent|wparam, 1 },
774     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE },
775     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
776     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
777     { WM_GETICON, sent|optional },
778     { WM_GETICON, sent|optional },
779     { WM_GETICON, sent|optional },
780     { WM_GETTEXT, sent|optional },
781     { HCBT_ACTIVATE, hook },
782     { WM_NCACTIVATE, sent|wparam, 0 },
783     { WM_GETICON, sent|optional },
784     { WM_GETICON, sent|optional },
785     { WM_GETICON, sent|optional },
786     { WM_GETTEXT, sent|optional },
787     { WM_ACTIVATE, sent|wparam, 0 },
788     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
789     { WM_WINDOWPOSCHANGING, sent|optional },
790     { HCBT_SETFOCUS, hook },
791     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
792     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
793     { WM_SETFOCUS, sent|parent|defwinproc },
794     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 },
795     { HCBT_DESTROYWND, hook },
796     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
797     { WM_DESTROY, sent },
798     { WM_NCDESTROY, sent },
799     { 0 }
800 };
801 /* Creation of a modal dialog that is resized inside WM_INITDIALOG (32) */
802 static const struct message WmCreateModalDialogResizeSeq[] = { /* FIXME: add */
803     /* (inside dialog proc, handling WM_INITDIALOG) */
804     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
805     { WM_NCCALCSIZE, sent },
806     { WM_NCACTIVATE, sent|parent|wparam, 0 },
807     { WM_GETTEXT, sent|defwinproc },
808     { WM_ACTIVATE, sent|parent|wparam, 0 },
809     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
810     { WM_WINDOWPOSCHANGING, sent|parent },
811     { WM_NCACTIVATE, sent|wparam, 1 },
812     { WM_ACTIVATE, sent|wparam, 1 },
813     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
814     { WM_SIZE, sent|defwinproc },
815     /* (setting focus) */
816     { WM_SHOWWINDOW, sent|wparam, 1 },
817     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
818     { WM_NCPAINT, sent },
819     { WM_GETTEXT, sent|defwinproc },
820     { WM_ERASEBKGND, sent },
821     { WM_CTLCOLORDLG, sent|defwinproc },
822     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
823     { WM_PAINT, sent },
824     /* (bunch of WM_CTLCOLOR* for each control) */
825     { WM_PAINT, sent|parent },
826     { WM_ENTERIDLE, sent|parent|wparam, 0 },
827     { WM_SETCURSOR, sent|parent },
828     { 0 }
829 };
830 /* SetMenu for NonVisible windows with size change*/
831 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
832     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
833     { WM_NCCALCSIZE, sent|wparam, 1 },
834     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
835     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW },
836     { WM_MOVE, sent|defwinproc },
837     { WM_SIZE, sent|defwinproc },
838     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
839     { WM_GETICON, sent|optional },
840     { WM_GETICON, sent|optional },
841     { WM_GETICON, sent|optional },
842     { WM_GETTEXT, sent|optional },
843     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
844     { 0 }
845 };
846 /* SetMenu for NonVisible windows with no size change */
847 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
848     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
849     { WM_NCCALCSIZE, sent|wparam, 1 },
850     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
851     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
852     { 0 }
853 };
854 /* SetMenu for Visible windows with size change */
855 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
856     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
857     { WM_NCCALCSIZE, sent|wparam, 1 },
858     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
859     { WM_NCPAINT, sent|wparam, 1 },
860     { WM_GETTEXT, sent|defwinproc|optional },
861     { WM_ERASEBKGND, sent|optional },
862     { WM_ACTIVATE, sent|optional },
863     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
864     { WM_MOVE, sent|defwinproc },
865     { WM_SIZE, sent|defwinproc },
866     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
867     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
868     { WM_NCPAINT, sent|wparam|optional, 1 },
869     { WM_ERASEBKGND, sent|optional },
870     { 0 }
871 };
872 /* SetMenu for Visible windows with no size change */
873 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
874     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
875     { WM_NCCALCSIZE, sent|wparam, 1 },
876     { WM_NCPAINT, sent|wparam, 1 },
877     { WM_GETTEXT, sent|defwinproc|optional },
878     { WM_ERASEBKGND, sent|optional },
879     { WM_ACTIVATE, sent|optional },
880     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
881     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
882     { 0 }
883 };
884 /* DrawMenuBar for a visible window */
885 static const struct message WmDrawMenuBarSeq[] =
886 {
887     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
888     { WM_NCCALCSIZE, sent|wparam, 1 },
889     { WM_NCPAINT, sent|wparam, 1 },
890     { WM_GETTEXT, sent|defwinproc|optional },
891     { WM_ERASEBKGND, sent|optional },
892     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
893     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
894     { 0 }
895 };
896
897 static const struct message WmSetRedrawFalseSeq[] =
898 {
899     { WM_SETREDRAW, sent|wparam, 0 },
900     { 0 }
901 };
902
903 static const struct message WmSetRedrawTrueSeq[] =
904 {
905     { WM_SETREDRAW, sent|wparam, 1 },
906     { 0 }
907 };
908
909 static const struct message WmEnableWindowSeq[] =
910 {
911     { WM_CANCELMODE, sent },
912     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
913     { WM_ENABLE, sent },
914     { 0 }
915 };
916
917 static const struct message WmGetScrollRangeSeq[] =
918 {
919     { SBM_GETRANGE, sent },
920     { 0 }
921 };
922 static const struct message WmGetScrollInfoSeq[] =
923 {
924     { SBM_GETSCROLLINFO, sent },
925     { 0 }
926 };
927 static const struct message WmSetScrollRangeSeq[] =
928 {
929     /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
930        sends SBM_SETSCROLLINFO.
931      */
932     { SBM_SETSCROLLINFO, sent },
933     { 0 }
934 };
935 /* SetScrollRange for a window without a non-client area */
936 static const struct message WmSetScrollRangeHSeq_empty[] =
937 {
938     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_HSCROLL, 0 },
939     { 0 }
940 };
941 static const struct message WmSetScrollRangeVSeq_empty[] =
942 {
943     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_VSCROLL, 0 },
944     { 0 }
945 };
946 static const struct message WmSetScrollRangeHVSeq[] =
947 {
948     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER },
949     { WM_NCCALCSIZE, sent|wparam, 1 },
950     { WM_GETTEXT, sent|defwinproc|optional },
951     { WM_ERASEBKGND, sent|optional },
952     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
953     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
954     { 0 }
955 };
956 /* SetScrollRange for a window with a non-client area */
957 static const struct message WmSetScrollRangeHV_NC_Seq[] =
958 {
959     { WM_WINDOWPOSCHANGING, sent, /*|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER*/ },
960     { WM_NCCALCSIZE, sent|wparam, 1 },
961     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
962     { WM_NCPAINT, sent|optional },
963     { WM_GETTEXT, sent|defwinproc|optional },
964     { WM_GETICON, sent|optional|defwinproc },
965     { WM_GETICON, sent|optional|defwinproc },
966     { WM_GETICON, sent|optional|defwinproc },
967     { WM_GETTEXT, sent|defwinproc|optional },
968     { WM_ERASEBKGND, sent|optional },
969     { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
970     { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|0x1000*/ },
971     { WM_SIZE, sent|defwinproc },
972     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
973     { WM_GETTEXT, sent|optional },
974     { WM_GETICON, sent|optional },
975     { WM_GETICON, sent|optional },
976     { WM_GETICON, sent|optional },
977     { WM_GETTEXT, sent|optional },
978     { WM_GETICON, sent|optional },
979     { WM_GETICON, sent|optional },
980     { WM_GETICON, sent|optional },
981     { WM_GETTEXT, sent|optional },
982     { WM_GETICON, sent|optional },
983     { WM_GETICON, sent|optional },
984     { WM_GETICON, sent|optional },
985     { WM_GETTEXT, sent|optional },
986     { 0 }
987 };
988 /* test if we receive the right sequence of messages */
989 /* after calling ShowWindow( SW_SHOWNA) */
990 static const struct message WmSHOWNAChildInvisParInvis[] = {
991     { WM_SHOWWINDOW, sent|wparam, 1 },
992     { 0 }
993 };
994 static const struct message WmSHOWNAChildVisParInvis[] = {
995     { WM_SHOWWINDOW, sent|wparam, 1 },
996     { 0 }
997 };
998 static const struct message WmSHOWNAChildVisParVis[] = {
999     { WM_SHOWWINDOW, sent|wparam, 1 },
1000     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER },
1001     { 0 }
1002 };
1003 static const struct message WmSHOWNAChildInvisParVis[] = {
1004     { WM_SHOWWINDOW, sent|wparam, 1 },
1005     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER},
1006     { WM_ERASEBKGND, sent|optional },
1007     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
1008     { 0 }
1009 };
1010 static const struct message WmSHOWNATopVisible[] = {
1011     { WM_SHOWWINDOW, sent|wparam, 1 },
1012     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1013     { 0 }
1014 };
1015 static const struct message WmSHOWNATopInvisible[] = {
1016     { WM_SHOWWINDOW, sent|wparam, 1 },
1017     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1018     { WM_NCPAINT, sent|wparam, 1 },
1019     { WM_GETTEXT, sent|defwinproc|optional },
1020     { WM_ERASEBKGND, sent|optional },
1021     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
1022     { WM_SIZE, sent },
1023     { WM_MOVE, sent },
1024     { 0 }
1025 };
1026
1027 static int after_end_dialog;
1028 static int sequence_cnt, sequence_size;
1029 static struct message* sequence;
1030 static int log_all_parent_messages;
1031
1032 static void add_message(const struct message *msg)
1033 {
1034     if (!sequence) 
1035     {
1036         sequence_size = 10;
1037         sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof (struct message) );
1038     }
1039     if (sequence_cnt == sequence_size) 
1040     {
1041         sequence_size *= 2;
1042         sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof (struct message) );
1043     }
1044     assert(sequence);
1045
1046     sequence[sequence_cnt].message = msg->message;
1047     sequence[sequence_cnt].flags = msg->flags;
1048     sequence[sequence_cnt].wParam = msg->wParam;
1049     sequence[sequence_cnt].lParam = msg->lParam;
1050
1051     sequence_cnt++;
1052 }
1053
1054 static void flush_sequence()
1055 {
1056     HeapFree(GetProcessHeap(), 0, sequence);
1057     sequence = 0;
1058     sequence_cnt = sequence_size = 0;
1059 }
1060
1061 #define ok_sequence( exp, contx, todo) \
1062         ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
1063
1064
1065 static void ok_sequence_(const struct message *expected, const char *context, int todo,
1066         const char *file, int line)
1067 {
1068     static const struct message end_of_sequence = { 0, 0, 0, 0 };
1069     const struct message *actual;
1070     int failcount = 0;
1071     
1072     add_message(&end_of_sequence);
1073
1074     actual = sequence;
1075
1076     while (expected->message && actual->message)
1077     {
1078         trace_( file, line)("expected %04x - actual %04x\n", expected->message, actual->message);
1079
1080         if (expected->message == actual->message)
1081         {
1082             if (expected->flags & wparam)
1083             {
1084                 if (expected->wParam != actual->wParam && todo)
1085                 {
1086                     todo_wine {
1087                         failcount ++;
1088                         ok_( file, line) (FALSE,
1089                             "%s: in msg 0x%04x expecting wParam 0x%x got 0x%x\n",
1090                             context, expected->message, expected->wParam, actual->wParam);
1091                     }
1092                 }
1093                 else
1094                 ok_( file, line) (expected->wParam == actual->wParam,
1095                      "%s: in msg 0x%04x expecting wParam 0x%x got 0x%x\n",
1096                      context, expected->message, expected->wParam, actual->wParam);
1097             }
1098             if (expected->flags & lparam)
1099                  ok_( file, line) (expected->lParam == actual->lParam,
1100                      "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
1101                      context, expected->message, expected->lParam, actual->lParam);
1102             ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
1103                 "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
1104                 context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
1105             ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
1106                 "%s: the msg 0x%04x should %shave been sent by BeginPaint\n",
1107                 context, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
1108             ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
1109                 "%s: the msg 0x%04x should have been %s\n",
1110                 context, expected->message, (expected->flags & posted) ? "posted" : "sent");
1111             ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
1112                 "%s: the msg 0x%04x was expected in %s\n",
1113                 context, expected->message, (expected->flags & parent) ? "parent" : "child");
1114             ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
1115                 "%s: the msg 0x%04x should have been sent by a hook\n",
1116                 context, expected->message);
1117             ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
1118                 "%s: the msg 0x%04x should have been sent by a winevent hook\n",
1119                 context, expected->message);
1120             expected++;
1121             actual++;
1122         }
1123         /* silently drop winevent messages if there is no support for them */
1124         else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
1125             expected++;
1126         else if (todo)
1127         {
1128             failcount++;
1129             todo_wine {
1130                 ok_( file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
1131                     context, expected->message, actual->message);
1132             }
1133             flush_sequence();
1134             return;
1135         }
1136         else
1137         {
1138             ok_( file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
1139                 context, expected->message, actual->message);
1140             expected++;
1141             actual++;
1142         }
1143     }
1144
1145     /* skip all optional trailing messages */
1146     while (expected->message && ((expected->flags & optional) ||
1147             ((expected->flags & winevent_hook) && !hEvent_hook)))
1148         expected++;
1149
1150     if (todo)
1151     {
1152         todo_wine {
1153             if (expected->message || actual->message) {
1154                 failcount++;
1155                 ok_( file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
1156                     context, expected->message, actual->message);
1157             }
1158         }
1159     }
1160     else
1161     {
1162         if (expected->message || actual->message)
1163             ok_( file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
1164                 context, expected->message, actual->message);
1165     }
1166     if( todo && !failcount) /* succeeded yet marked todo */
1167         todo_wine {
1168             ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
1169         }
1170
1171     flush_sequence();
1172 }
1173
1174 /******************************** MDI test **********************************/
1175
1176 /* CreateWindow for MDI frame window, initially visible */
1177 static const struct message WmCreateMDIframeSeq[] = {
1178     { HCBT_CREATEWND, hook },
1179     { WM_GETMINMAXINFO, sent },
1180     { WM_NCCREATE, sent },
1181     { WM_NCCALCSIZE, sent|wparam, 0 },
1182     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1183     { WM_CREATE, sent },
1184     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1185     { WM_SHOWWINDOW, sent|wparam, 1 },
1186     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1187     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1188     { HCBT_ACTIVATE, hook },
1189     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1190     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1191     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1192     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* Win9x */
1193     { WM_ACTIVATEAPP, sent|wparam, 1 },
1194     { WM_NCACTIVATE, sent|wparam, 1 },
1195     { WM_ACTIVATE, sent|wparam, 1 },
1196     { HCBT_SETFOCUS, hook },
1197     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1198     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1199     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
1200     /* Win9x adds SWP_NOZORDER below */
1201     { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
1202     { WM_SIZE, sent },
1203     { WM_MOVE, sent },
1204     { 0 }
1205 };
1206 /* DestroyWindow for MDI frame window, initially visible */
1207 static const struct message WmDestroyMDIframeSeq[] = {
1208     { HCBT_DESTROYWND, hook },
1209     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1210     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1211     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1212     { WM_NCACTIVATE, sent|wparam, 0 },
1213     { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
1214     { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
1215     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
1216     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1217     { WM_DESTROY, sent },
1218     { WM_NCDESTROY, sent },
1219     { 0 }
1220 };
1221 /* CreateWindow for MDI client window, initially visible */
1222 static const struct message WmCreateMDIclientSeq[] = {
1223     { HCBT_CREATEWND, hook },
1224     { WM_NCCREATE, sent },
1225     { WM_NCCALCSIZE, sent|wparam, 0 },
1226     { WM_CREATE, sent },
1227     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1228     { WM_SIZE, sent },
1229     { WM_MOVE, sent },
1230     { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
1231     { WM_SHOWWINDOW, sent|wparam, 1 },
1232     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE|SWP_NOMOVE },
1233     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1234     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1235     { 0 }
1236 };
1237 /* DestroyWindow for MDI client window, initially visible */
1238 static const struct message WmDestroyMDIclientSeq[] = {
1239     { HCBT_DESTROYWND, hook },
1240     { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
1241     { WM_SHOWWINDOW, sent|wparam, 0 },
1242     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1243     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1244     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1245     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1246     { WM_DESTROY, sent },
1247     { WM_NCDESTROY, sent },
1248     { 0 }
1249 };
1250 /* CreateWindow for MDI child window, initially visible */
1251 static const struct message WmCreateMDIchildVisibleSeq[] = {
1252     { HCBT_CREATEWND, hook },
1253     { WM_NCCREATE, sent }, 
1254     { WM_NCCALCSIZE, sent|wparam, 0 },
1255     { WM_CREATE, sent },
1256     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1257     { WM_SIZE, sent },
1258     { WM_MOVE, sent },
1259     /* Win2k sends wparam set to
1260      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1261      * while Win9x doesn't bother to set child window id according to
1262      * CLIENTCREATESTRUCT.idFirstChild
1263      */
1264     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1265     { WM_SHOWWINDOW, sent|wparam, 1 },
1266     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1267     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1268     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1269     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1270     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1271     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1272     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1273
1274     /* Win9x: message sequence terminates here. */
1275
1276     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1277     { HCBT_SETFOCUS, hook }, /* in MDI client */
1278     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1279     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1280     { WM_SETFOCUS, sent }, /* in MDI client */
1281     { HCBT_SETFOCUS, hook },
1282     { WM_KILLFOCUS, sent }, /* in MDI client */
1283     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1284     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1285     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1286     { WM_SETFOCUS, sent|defwinproc },
1287     { WM_MDIACTIVATE, sent|defwinproc },
1288     { 0 }
1289 };
1290 /* DestroyWindow for MDI child window, initially visible */
1291 static const struct message WmDestroyMDIchildVisibleSeq[] = {
1292     { HCBT_DESTROYWND, hook },
1293     /* Win2k sends wparam set to
1294      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1295      * while Win9x doesn't bother to set child window id according to
1296      * CLIENTCREATESTRUCT.idFirstChild
1297      */
1298     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1299     { WM_SHOWWINDOW, sent|wparam, 0 },
1300     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1301     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1302     { WM_ERASEBKGND, sent|parent|optional },
1303     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1304
1305     /* { WM_DESTROY, sent }
1306      * Win9x: message sequence terminates here.
1307      */
1308
1309     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1310     { WM_KILLFOCUS, sent },
1311     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1312     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1313     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1314     { WM_SETFOCUS, sent }, /* in MDI client */
1315
1316     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1317     { WM_KILLFOCUS, sent }, /* in MDI client */
1318     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1319     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1320     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1321     { WM_SETFOCUS, sent }, /* in MDI client */
1322
1323     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1324
1325     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1326     { WM_KILLFOCUS, sent },
1327     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1328     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1329     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1330     { WM_SETFOCUS, sent }, /* in MDI client */
1331
1332     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1333     { WM_KILLFOCUS, sent }, /* in MDI client */
1334     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1335     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1336     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1337     { WM_SETFOCUS, sent }, /* in MDI client */
1338
1339     { WM_DESTROY, sent },
1340
1341     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1342     { WM_KILLFOCUS, sent },
1343     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1344     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1345     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1346     { WM_SETFOCUS, sent }, /* in MDI client */
1347
1348     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1349     { WM_KILLFOCUS, sent }, /* in MDI client */
1350     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1351     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1352     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1353     { WM_SETFOCUS, sent }, /* in MDI client */
1354
1355     { WM_NCDESTROY, sent },
1356     { 0 }
1357 };
1358 /* CreateWindow for MDI child window, initially invisible */
1359 static const struct message WmCreateMDIchildInvisibleSeq[] = {
1360     { HCBT_CREATEWND, hook },
1361     { WM_NCCREATE, sent }, 
1362     { WM_NCCALCSIZE, sent|wparam, 0 },
1363     { WM_CREATE, sent },
1364     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1365     { WM_SIZE, sent },
1366     { WM_MOVE, sent },
1367     /* Win2k sends wparam set to
1368      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1369      * while Win9x doesn't bother to set child window id according to
1370      * CLIENTCREATESTRUCT.idFirstChild
1371      */
1372     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1373     { 0 }
1374 };
1375 /* DestroyWindow for MDI child window, initially invisible */
1376 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
1377     { HCBT_DESTROYWND, hook },
1378     /* Win2k sends wparam set to
1379      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1380      * while Win9x doesn't bother to set child window id according to
1381      * CLIENTCREATESTRUCT.idFirstChild
1382      */
1383     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1384     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1385     { WM_DESTROY, sent },
1386     { WM_NCDESTROY, sent },
1387     { 0 }
1388 };
1389 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
1390 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
1391     { HCBT_CREATEWND, hook },
1392     { WM_NCCREATE, sent }, 
1393     { WM_NCCALCSIZE, sent|wparam, 0 },
1394     { WM_CREATE, sent },
1395     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1396     { WM_SIZE, sent },
1397     { WM_MOVE, sent },
1398     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1399     { WM_GETMINMAXINFO, sent },
1400     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
1401     { WM_NCCALCSIZE, sent|wparam, 1 },
1402     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1403     { WM_SIZE, sent|defwinproc },
1404      /* in MDI frame */
1405     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1406     { WM_NCCALCSIZE, sent|wparam, 1 },
1407     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1408     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1409     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
1410     /* Win2k sends wparam set to
1411      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1412      * while Win9x doesn't bother to set child window id according to
1413      * CLIENTCREATESTRUCT.idFirstChild
1414      */
1415     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1416     { WM_SHOWWINDOW, sent|wparam, 1 },
1417     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1418     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1419     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1420     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1421     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1422     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1423     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1424
1425     /* Win9x: message sequence terminates here. */
1426
1427     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1428     { HCBT_SETFOCUS, hook }, /* in MDI client */
1429     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1430     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1431     { WM_SETFOCUS, sent }, /* in MDI client */
1432     { HCBT_SETFOCUS, hook },
1433     { WM_KILLFOCUS, sent }, /* in MDI client */
1434     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1435     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1436     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1437     { WM_SETFOCUS, sent|defwinproc },
1438     { WM_MDIACTIVATE, sent|defwinproc },
1439      /* in MDI frame */
1440     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1441     { WM_NCCALCSIZE, sent|wparam, 1 },
1442     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1443     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1444     { 0 }
1445 };
1446 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
1447 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
1448     /* restore the 1st MDI child */
1449     { WM_SETREDRAW, sent|wparam, 0 },
1450     { HCBT_MINMAX, hook },
1451     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
1452     { WM_NCCALCSIZE, sent|wparam, 1 },
1453     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1454     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1455     { WM_SIZE, sent|defwinproc },
1456      /* in MDI frame */
1457     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1458     { WM_NCCALCSIZE, sent|wparam, 1 },
1459     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1460     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1461     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
1462     { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
1463     /* create the 2nd MDI child */
1464     { HCBT_CREATEWND, hook },
1465     { WM_NCCREATE, sent }, 
1466     { WM_NCCALCSIZE, sent|wparam, 0 },
1467     { WM_CREATE, sent },
1468     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1469     { WM_SIZE, sent },
1470     { WM_MOVE, sent },
1471     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1472     { WM_GETMINMAXINFO, sent },
1473     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
1474     { WM_NCCALCSIZE, sent|wparam, 1 },
1475     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1476     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1477     { WM_SIZE, sent|defwinproc },
1478      /* in MDI frame */
1479     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1480     { WM_NCCALCSIZE, sent|wparam, 1 },
1481     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1482     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1483     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
1484     /* Win2k sends wparam set to
1485      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1486      * while Win9x doesn't bother to set child window id according to
1487      * CLIENTCREATESTRUCT.idFirstChild
1488      */
1489     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1490     { WM_SHOWWINDOW, sent|wparam, 1 },
1491     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1492     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1493     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1494     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1495     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1496     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1497
1498     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
1499     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
1500
1501     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1502
1503     /* Win9x: message sequence terminates here. */
1504
1505     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1506     { HCBT_SETFOCUS, hook },
1507     { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
1508     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
1509     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1510     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1511     { WM_SETFOCUS, sent }, /* in MDI client */
1512     { HCBT_SETFOCUS, hook },
1513     { WM_KILLFOCUS, sent }, /* in MDI client */
1514     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1515     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1516     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1517     { WM_SETFOCUS, sent|defwinproc },
1518
1519     { WM_MDIACTIVATE, sent|defwinproc },
1520      /* in MDI frame */
1521     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1522     { WM_NCCALCSIZE, sent|wparam, 1 },
1523     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1524     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1525     { 0 }
1526 };
1527 /* WM_MDICREATE MDI child window, initially visible and maximized */
1528 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
1529     { WM_MDICREATE, sent },
1530     { HCBT_CREATEWND, hook },
1531     { WM_NCCREATE, sent }, 
1532     { WM_NCCALCSIZE, sent|wparam, 0 },
1533     { WM_CREATE, sent },
1534     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1535     { WM_SIZE, sent },
1536     { WM_MOVE, sent },
1537     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1538     { WM_GETMINMAXINFO, sent },
1539     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
1540     { WM_NCCALCSIZE, sent|wparam, 1 },
1541     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1542     { WM_SIZE, sent|defwinproc },
1543
1544      /* in MDI frame */
1545     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1546     { WM_NCCALCSIZE, sent|wparam, 1 },
1547     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1548     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1549     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
1550
1551     /* Win2k sends wparam set to
1552      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1553      * while Win9x doesn't bother to set child window id according to
1554      * CLIENTCREATESTRUCT.idFirstChild
1555      */
1556     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1557     { WM_SHOWWINDOW, sent|wparam, 1 },
1558     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1559
1560     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1561
1562     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1563     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1564     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1565
1566     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1567     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1568
1569     /* Win9x: message sequence terminates here. */
1570
1571     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1572     { HCBT_SETFOCUS, hook }, /* in MDI client */
1573     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1574     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1575     { WM_SETFOCUS, sent }, /* in MDI client */
1576     { HCBT_SETFOCUS, hook },
1577     { WM_KILLFOCUS, sent }, /* in MDI client */
1578     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1579     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1580     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1581     { WM_SETFOCUS, sent|defwinproc },
1582
1583     { WM_MDIACTIVATE, sent|defwinproc },
1584
1585      /* in MDI child */
1586     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1587     { WM_NCCALCSIZE, sent|wparam, 1 },
1588     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1589     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1590
1591      /* in MDI frame */
1592     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1593     { WM_NCCALCSIZE, sent|wparam, 1 },
1594     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1595     { WM_MOVE, sent|defwinproc },
1596     { WM_SIZE, sent|defwinproc },
1597
1598      /* in MDI client */
1599     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
1600     { WM_NCCALCSIZE, sent|wparam, 1 },
1601     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
1602     { WM_SIZE, sent },
1603
1604      /* in MDI child */
1605     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
1606     { WM_NCCALCSIZE, sent|wparam, 1 },
1607     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
1608     { WM_SIZE, sent|defwinproc },
1609
1610     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
1611     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
1612     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1613
1614     { 0 }
1615 };
1616 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
1617 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
1618     { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
1619     { HCBT_SYSCOMMAND, hook },
1620     { WM_CLOSE, sent|defwinproc },
1621     { WM_MDIDESTROY, sent }, /* in MDI client */
1622
1623     /* bring the 1st MDI child to top */
1624     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
1625     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
1626
1627     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1628
1629     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
1630     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
1631     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
1632
1633     /* maximize the 1st MDI child */
1634     { HCBT_MINMAX, hook },
1635     { WM_GETMINMAXINFO, sent|defwinproc },
1636     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|0x8000 },
1637     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
1638     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
1639     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1640     { WM_SIZE, sent|defwinproc },
1641
1642     /* restore the 2nd MDI child */
1643     { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
1644     { HCBT_MINMAX, hook },
1645     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOZORDER|0x8000 },
1646     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
1647
1648     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1649
1650     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1651     { WM_SIZE, sent|defwinproc },
1652
1653     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1654
1655     { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
1656      /* in MDI frame */
1657     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1658     { WM_NCCALCSIZE, sent|wparam, 1 },
1659     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1660     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1661     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
1662
1663     /* bring the 1st MDI child to top */
1664     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1665     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1666     { HCBT_SETFOCUS, hook },
1667     { WM_KILLFOCUS, sent|defwinproc },
1668     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
1669     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1670     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1671     { WM_SETFOCUS, sent }, /* in MDI client */
1672     { HCBT_SETFOCUS, hook },
1673     { WM_KILLFOCUS, sent }, /* in MDI client */
1674     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1675     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1676     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1677     { WM_SETFOCUS, sent|defwinproc },
1678     { WM_MDIACTIVATE, sent|defwinproc },
1679     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1680
1681     /* apparently ShowWindow(SW_SHOW) on an MDI client */
1682     { WM_SHOWWINDOW, sent|wparam, 1 },
1683     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1684     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1685     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1686     { WM_MDIREFRESHMENU, sent },
1687
1688     { HCBT_DESTROYWND, hook },
1689     /* Win2k sends wparam set to
1690      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1691      * while Win9x doesn't bother to set child window id according to
1692      * CLIENTCREATESTRUCT.idFirstChild
1693      */
1694     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1695     { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
1696     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1697     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1698     { WM_ERASEBKGND, sent|parent|optional },
1699     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1700
1701     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1702     { WM_DESTROY, sent|defwinproc },
1703     { WM_NCDESTROY, sent|defwinproc },
1704     { 0 }
1705 };
1706 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
1707 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
1708     { WM_MDIDESTROY, sent }, /* in MDI client */
1709     { WM_SHOWWINDOW, sent|wparam, 0 },
1710     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1711     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1712     { WM_ERASEBKGND, sent|parent|optional },
1713     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1714
1715     { HCBT_SETFOCUS, hook },
1716     { WM_KILLFOCUS, sent },
1717     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1718     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1719     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1720     { WM_SETFOCUS, sent }, /* in MDI client */
1721     { HCBT_SETFOCUS, hook },
1722     { WM_KILLFOCUS, sent }, /* in MDI client */
1723     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1724     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1725     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1726     { WM_SETFOCUS, sent },
1727
1728      /* in MDI child */
1729     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1730     { WM_NCCALCSIZE, sent|wparam, 1 },
1731     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1732     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
1733
1734      /* in MDI frame */
1735     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1736     { WM_NCCALCSIZE, sent|wparam, 1 },
1737     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1738     { WM_MOVE, sent|defwinproc },
1739     { WM_SIZE, sent|defwinproc },
1740
1741      /* in MDI client */
1742     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
1743     { WM_NCCALCSIZE, sent|wparam, 1 },
1744     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
1745     { WM_SIZE, sent },
1746
1747      /* in MDI child */
1748     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
1749     { WM_NCCALCSIZE, sent|wparam, 1 },
1750     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
1751     { WM_SIZE, sent|defwinproc },
1752
1753      /* in MDI child */
1754     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1755     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
1756     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1757     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
1758
1759      /* in MDI frame */
1760     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1761     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
1762     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1763     { WM_MOVE, sent|defwinproc },
1764     { WM_SIZE, sent|defwinproc },
1765
1766      /* in MDI client */
1767     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
1768     { WM_NCCALCSIZE, sent|wparam, 1 },
1769     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
1770     { WM_SIZE, sent },
1771
1772      /* in MDI child */
1773     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOZORDER },
1774     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
1775     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
1776     { WM_SIZE, sent|defwinproc },
1777     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
1778     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
1779     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1780     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
1781     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
1782     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1783
1784      /* in MDI frame */
1785     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1786     { WM_NCCALCSIZE, sent|wparam, 1 },
1787     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1788     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1789
1790     { WM_NCACTIVATE, sent|wparam, 0 },
1791     { WM_MDIACTIVATE, sent },
1792
1793     { HCBT_MINMAX, hook },
1794     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|0x8000 },
1795     { WM_NCCALCSIZE, sent|wparam, 1 },
1796
1797     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1798
1799     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1800     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE|0x8000 },
1801     { WM_SIZE, sent|defwinproc },
1802
1803      /* in MDI child */
1804     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1805     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
1806     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1807     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
1808
1809      /* in MDI frame */
1810     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1811     { WM_NCCALCSIZE, sent|wparam, 1 },
1812     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1813     { WM_MOVE, sent|defwinproc },
1814     { WM_SIZE, sent|defwinproc },
1815
1816      /* in MDI client */
1817     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
1818     { WM_NCCALCSIZE, sent|wparam, 1 },
1819     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
1820     { WM_SIZE, sent },
1821     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
1822     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
1823     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1824
1825     { HCBT_SETFOCUS, hook },
1826     { WM_KILLFOCUS, sent },
1827     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1828     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1829     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1830     { WM_SETFOCUS, sent }, /* in MDI client */
1831
1832     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
1833
1834     { HCBT_DESTROYWND, hook },
1835     /* Win2k sends wparam set to
1836      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1837      * while Win9x doesn't bother to set child window id according to
1838      * CLIENTCREATESTRUCT.idFirstChild
1839      */
1840     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1841
1842     { WM_SHOWWINDOW, sent|wparam, 0 },
1843     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1844     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1845     { WM_ERASEBKGND, sent|parent|optional },
1846     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1847
1848     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1849     { WM_DESTROY, sent },
1850     { WM_NCDESTROY, sent },
1851     { 0 }
1852 };
1853 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
1854 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
1855     { HCBT_MINMAX, hook },
1856     { WM_GETMINMAXINFO, sent },
1857     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
1858     { WM_NCCALCSIZE, sent|wparam, 1 },
1859     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1860     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1861
1862     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1863     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1864     { HCBT_SETFOCUS, hook },
1865     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1866     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1867     { WM_SETFOCUS, sent }, /* in MDI client */
1868     { HCBT_SETFOCUS, hook },
1869     { WM_KILLFOCUS, sent }, /* in MDI client */
1870     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1871     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1872     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1873     { WM_SETFOCUS, sent|defwinproc },
1874     { WM_MDIACTIVATE, sent|defwinproc },
1875     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1876     { WM_SIZE, sent|defwinproc },
1877      /* in MDI frame */
1878     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1879     { WM_NCCALCSIZE, sent|wparam, 1 },
1880     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1881     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1882     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
1883     { 0 }
1884 };
1885 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
1886 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
1887     { HCBT_MINMAX, hook },
1888     { WM_GETMINMAXINFO, sent },
1889     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
1890     { WM_NCCALCSIZE, sent|wparam, 1 },
1891     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1892     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1893     { WM_SIZE, sent|defwinproc },
1894      /* in MDI frame */
1895     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1896     { WM_NCCALCSIZE, sent|wparam, 1 },
1897     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1898     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1899     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
1900     { 0 }
1901 };
1902 /* ShowWindow(SW_RESTORE) for a visible MDI child window */
1903 static const struct message WmRestoreMDIchildVisibleSeq[] = {
1904     { HCBT_MINMAX, hook },
1905     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
1906     { WM_NCCALCSIZE, sent|wparam, 1 },
1907     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1908     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1909     { WM_SIZE, sent|defwinproc },
1910      /* in MDI frame */
1911     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1912     { WM_NCCALCSIZE, sent|wparam, 1 },
1913     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1914     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1915     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
1916     { 0 }
1917 };
1918 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
1919 static const struct message WmRestoreMDIchildInisibleSeq[] = {
1920     { HCBT_MINMAX, hook },
1921     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
1922     { WM_NCCALCSIZE, sent|wparam, 1 },
1923     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1924     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1925     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1926     { WM_SIZE, sent|defwinproc },
1927      /* in MDI frame */
1928     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1929     { WM_NCCALCSIZE, sent|wparam, 1 },
1930     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1931     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1932     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
1933     { 0 }
1934 };
1935
1936 static HWND mdi_client;
1937 static WNDPROC old_mdi_client_proc;
1938
1939 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1940 {
1941     struct message msg;
1942
1943     /* do not log painting messages */
1944     if (message != WM_PAINT &&
1945         message != WM_ERASEBKGND &&
1946         message != WM_NCPAINT &&
1947         message != WM_NCHITTEST &&
1948         message != WM_GETTEXT &&
1949         message != WM_MDIGETACTIVE)
1950     {
1951         trace("mdi client: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1952
1953         switch (message)
1954         {
1955             case WM_WINDOWPOSCHANGING:
1956             case WM_WINDOWPOSCHANGED:
1957             {
1958                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
1959
1960                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
1961                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
1962                       winpos->hwnd, winpos->hwndInsertAfter,
1963                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
1964
1965                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
1966                  * in the high word for internal purposes
1967                  */
1968                 wParam = winpos->flags & 0xffff;
1969                 break;
1970             }
1971         }
1972
1973         msg.message = message;
1974         msg.flags = sent|wparam|lparam;
1975         msg.wParam = wParam;
1976         msg.lParam = lParam;
1977         add_message(&msg);
1978     }
1979
1980     return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
1981 }
1982
1983 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1984 {
1985     static long defwndproc_counter = 0;
1986     LRESULT ret;
1987     struct message msg;
1988
1989     /* do not log painting messages */
1990     if (message != WM_PAINT &&
1991         message != WM_ERASEBKGND &&
1992         message != WM_NCPAINT &&
1993         message != WM_NCHITTEST &&
1994         message != WM_GETTEXT)
1995     {
1996         trace("mdi child: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1997
1998         switch (message)
1999         {
2000             case WM_WINDOWPOSCHANGING:
2001             case WM_WINDOWPOSCHANGED:
2002             {
2003                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
2004
2005                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
2006                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
2007                       winpos->hwnd, winpos->hwndInsertAfter,
2008                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
2009
2010                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2011                  * in the high word for internal purposes
2012                  */
2013                 wParam = winpos->flags & 0xffff;
2014                 break;
2015             }
2016
2017             case WM_MDIACTIVATE:
2018             {
2019                 HWND active, client = GetParent(hwnd);
2020
2021                 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
2022
2023                 if (hwnd == (HWND)lParam) /* if we are being activated */
2024                     ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
2025                 else
2026                     ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
2027                 break;
2028             }
2029         }
2030
2031         msg.message = message;
2032         msg.flags = sent|wparam|lparam;
2033         if (defwndproc_counter) msg.flags |= defwinproc;
2034         msg.wParam = wParam;
2035         msg.lParam = lParam;
2036         add_message(&msg);
2037     }
2038
2039     defwndproc_counter++;
2040     ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
2041     defwndproc_counter--;
2042
2043     return ret;
2044 }
2045
2046 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2047 {
2048     static long defwndproc_counter = 0;
2049     LRESULT ret;
2050     struct message msg;
2051
2052     /* do not log painting messages */
2053     if (message != WM_PAINT &&
2054         message != WM_ERASEBKGND &&
2055         message != WM_NCPAINT &&
2056         message != WM_NCHITTEST &&
2057         message != WM_GETTEXT)
2058     {
2059         trace("mdi frame: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2060
2061         switch (message)
2062         {
2063             case WM_WINDOWPOSCHANGING:
2064             case WM_WINDOWPOSCHANGED:
2065             {
2066                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
2067
2068                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
2069                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
2070                       winpos->hwnd, winpos->hwndInsertAfter,
2071                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
2072
2073                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2074                  * in the high word for internal purposes
2075                  */
2076                 wParam = winpos->flags & 0xffff;
2077                 break;
2078             }
2079         }
2080
2081         msg.message = message;
2082         msg.flags = sent|wparam|lparam;
2083         if (defwndproc_counter) msg.flags |= defwinproc;
2084         msg.wParam = wParam;
2085         msg.lParam = lParam;
2086         add_message(&msg);
2087     }
2088
2089     defwndproc_counter++;
2090     ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
2091     defwndproc_counter--;
2092
2093     return ret;
2094 }
2095
2096 static BOOL mdi_RegisterWindowClasses(void)
2097 {
2098     WNDCLASSA cls;
2099
2100     cls.style = 0;
2101     cls.lpfnWndProc = mdi_frame_wnd_proc;
2102     cls.cbClsExtra = 0;
2103     cls.cbWndExtra = 0;
2104     cls.hInstance = GetModuleHandleA(0);
2105     cls.hIcon = 0;
2106     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
2107     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
2108     cls.lpszMenuName = NULL;
2109     cls.lpszClassName = "MDI_frame_class";
2110     if (!RegisterClassA(&cls)) return FALSE;
2111
2112     cls.lpfnWndProc = mdi_child_wnd_proc;
2113     cls.lpszClassName = "MDI_child_class";
2114     if (!RegisterClassA(&cls)) return FALSE;
2115
2116     if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
2117     old_mdi_client_proc = cls.lpfnWndProc;
2118     cls.hInstance = GetModuleHandleA(0);
2119     cls.lpfnWndProc = mdi_client_hook_proc;
2120     cls.lpszClassName = "MDI_client_class";
2121     if (!RegisterClassA(&cls)) assert(0);
2122
2123     return TRUE;
2124 }
2125
2126 static void test_mdi_messages(void)
2127 {
2128     MDICREATESTRUCTA mdi_cs;
2129     CLIENTCREATESTRUCT client_cs;
2130     HWND mdi_frame, mdi_child, mdi_child2, active_child;
2131     BOOL zoomed;
2132     HMENU hMenu = CreateMenu();
2133
2134     assert(mdi_RegisterWindowClasses());
2135
2136     flush_sequence();
2137
2138     trace("creating MDI frame window\n");
2139     mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
2140                                 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
2141                                 WS_MAXIMIZEBOX | WS_VISIBLE,
2142                                 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
2143                                 GetDesktopWindow(), hMenu,
2144                                 GetModuleHandleA(0), NULL);
2145     assert(mdi_frame);
2146     ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", TRUE);
2147
2148     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2149     ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
2150
2151     trace("creating MDI client window\n");
2152     client_cs.hWindowMenu = 0;
2153     client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
2154     mdi_client = CreateWindowExA(0, "MDI_client_class",
2155                                  NULL,
2156                                  WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
2157                                  0, 0, 0, 0,
2158                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
2159     assert(mdi_client);
2160     ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
2161
2162     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2163     ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
2164
2165     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2166     ok(!active_child, "wrong active MDI child %p\n", active_child);
2167     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2168
2169     SetFocus(0);
2170     flush_sequence();
2171
2172     trace("creating invisible MDI child window\n");
2173     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
2174                                 WS_CHILD,
2175                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
2176                                 mdi_client, 0, GetModuleHandleA(0), NULL);
2177     assert(mdi_child);
2178
2179     flush_sequence();
2180     ShowWindow(mdi_child, SW_SHOWNORMAL);
2181     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
2182
2183     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
2184     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
2185
2186     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2187     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2188
2189     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2190     ok(!active_child, "wrong active MDI child %p\n", active_child);
2191     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2192
2193     ShowWindow(mdi_child, SW_HIDE);
2194     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
2195     flush_sequence();
2196
2197     ShowWindow(mdi_child, SW_SHOW);
2198     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
2199
2200     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
2201     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
2202
2203     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2204     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2205
2206     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2207     ok(!active_child, "wrong active MDI child %p\n", active_child);
2208     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2209
2210     DestroyWindow(mdi_child);
2211     flush_sequence();
2212
2213     trace("creating visible MDI child window\n");
2214     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
2215                                 WS_CHILD | WS_VISIBLE,
2216                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
2217                                 mdi_client, 0, GetModuleHandleA(0), NULL);
2218     assert(mdi_child);
2219     ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", TRUE);
2220
2221     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
2222     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
2223
2224     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2225     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
2226
2227     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2228     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
2229     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2230     flush_sequence();
2231
2232     DestroyWindow(mdi_child);
2233     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
2234
2235     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2236     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2237
2238     /* Win2k: MDI client still returns a just destroyed child as active
2239      * Win9x: MDI client returns 0
2240      */
2241     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2242     ok(active_child == mdi_child || /* win2k */
2243        !active_child, /* win9x */
2244        "wrong active MDI child %p\n", active_child);
2245     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2246
2247     flush_sequence();
2248
2249     trace("creating invisible MDI child window\n");
2250     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
2251                                 WS_CHILD,
2252                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
2253                                 mdi_client, 0, GetModuleHandleA(0), NULL);
2254     assert(mdi_child2);
2255     ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
2256
2257     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
2258     ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
2259
2260     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2261     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2262
2263     /* Win2k: MDI client still returns a just destroyed child as active
2264      * Win9x: MDI client returns mdi_child2
2265      */
2266     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2267     ok(active_child == mdi_child || /* win2k */
2268        active_child == mdi_child2, /* win9x */
2269        "wrong active MDI child %p\n", active_child);
2270     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2271     flush_sequence();
2272
2273     ShowWindow(mdi_child2, SW_MAXIMIZE);
2274     ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", TRUE);
2275
2276     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
2277     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
2278
2279     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2280     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
2281     ok(zoomed, "wrong zoomed state %d\n", zoomed);
2282     flush_sequence();
2283
2284     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2285     ok(GetFocus() == mdi_child2 || /* win2k */
2286        GetFocus() == 0, /* win9x */
2287        "wrong focus window %p\n", GetFocus());
2288
2289     SetFocus(0);
2290     flush_sequence();
2291
2292     ShowWindow(mdi_child2, SW_HIDE);
2293     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
2294
2295     ShowWindow(mdi_child2, SW_RESTORE);
2296     ok_sequence(WmRestoreMDIchildInisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", TRUE);
2297     flush_sequence();
2298
2299     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
2300     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
2301
2302     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2303     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
2304     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2305     flush_sequence();
2306
2307     SetFocus(0);
2308     flush_sequence();
2309
2310     ShowWindow(mdi_child2, SW_HIDE);
2311     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
2312
2313     ShowWindow(mdi_child2, SW_SHOW);
2314     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
2315
2316     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2317     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2318
2319     ShowWindow(mdi_child2, SW_MAXIMIZE);
2320     ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", TRUE);
2321
2322     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2323     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2324
2325     ShowWindow(mdi_child2, SW_RESTORE);
2326     ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):MDI child", TRUE);
2327
2328     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2329     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2330
2331     SetFocus(0);
2332     flush_sequence();
2333
2334     ShowWindow(mdi_child2, SW_HIDE);
2335     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
2336
2337     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2338     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2339
2340     DestroyWindow(mdi_child2);
2341     ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
2342
2343     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2344     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2345
2346     /* test for maximized MDI children */
2347     trace("creating maximized visible MDI child window 1\n");
2348     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
2349                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
2350                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
2351                                 mdi_client, 0, GetModuleHandleA(0), NULL);
2352     assert(mdi_child);
2353     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
2354     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
2355
2356     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2357     ok(GetFocus() == mdi_child || /* win2k */
2358        GetFocus() == 0, /* win9x */
2359        "wrong focus window %p\n", GetFocus());
2360
2361     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2362     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
2363     ok(zoomed, "wrong zoomed state %d\n", zoomed);
2364     flush_sequence();
2365
2366     trace("creating maximized visible MDI child window 2\n");
2367     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
2368                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
2369                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
2370                                 mdi_client, 0, GetModuleHandleA(0), NULL);
2371     assert(mdi_child2);
2372     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
2373     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
2374     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
2375
2376     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2377     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
2378
2379     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2380     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
2381     ok(zoomed, "wrong zoomed state %d\n", zoomed);
2382     flush_sequence();
2383
2384     trace("destroying maximized visible MDI child window 2\n");
2385     DestroyWindow(mdi_child2);
2386     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
2387
2388     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
2389
2390     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2391     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2392
2393     /* Win2k: MDI client still returns a just destroyed child as active
2394      * Win9x: MDI client returns 0
2395      */
2396     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2397     ok(active_child == mdi_child2 || /* win2k */
2398        !active_child, /* win9x */
2399        "wrong active MDI child %p\n", active_child);
2400     flush_sequence();
2401
2402     ShowWindow(mdi_child, SW_MAXIMIZE);
2403     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
2404     flush_sequence();
2405
2406     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2407     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
2408
2409     trace("re-creating maximized visible MDI child window 2\n");
2410     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
2411                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
2412                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
2413                                 mdi_client, 0, GetModuleHandleA(0), NULL);
2414     assert(mdi_child2);
2415     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
2416     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
2417     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
2418
2419     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2420     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
2421
2422     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2423     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
2424     ok(zoomed, "wrong zoomed state %d\n", zoomed);
2425     flush_sequence();
2426
2427     SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
2428     ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
2429     ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
2430
2431     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
2432     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2433     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
2434
2435     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2436     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
2437     ok(zoomed, "wrong zoomed state %d\n", zoomed);
2438     flush_sequence();
2439
2440     DestroyWindow(mdi_child);
2441     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
2442
2443     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2444     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2445
2446     /* Win2k: MDI client still returns a just destroyed child as active
2447      * Win9x: MDI client returns 0
2448      */
2449     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2450     ok(active_child == mdi_child || /* win2k */
2451        !active_child, /* win9x */
2452        "wrong active MDI child %p\n", active_child);
2453     flush_sequence();
2454     /* end of test for maximized MDI children */
2455
2456     mdi_cs.szClass = "MDI_child_Class";
2457     mdi_cs.szTitle = "MDI child";
2458     mdi_cs.hOwner = GetModuleHandleA(0);
2459     mdi_cs.x = 0;
2460     mdi_cs.y = 0;
2461     mdi_cs.cx = CW_USEDEFAULT;
2462     mdi_cs.cy = CW_USEDEFAULT;
2463     mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
2464     mdi_cs.lParam = 0;
2465     mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
2466     ok(mdi_child != 0, "MDI child creation failed\n");
2467     ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
2468
2469     ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
2470
2471     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2472     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
2473
2474     ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
2475     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2476     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
2477
2478     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2479     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
2480     ok(zoomed, "wrong zoomed state %d\n", zoomed);
2481     flush_sequence();
2482
2483     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
2484     ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
2485
2486     ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
2487     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2488     ok(!active_child, "wrong active MDI child %p\n", active_child);
2489
2490     SetFocus(0);
2491     flush_sequence();
2492
2493     DestroyWindow(mdi_client);
2494     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
2495
2496     DestroyWindow(mdi_frame);
2497     ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
2498 }
2499 /************************* End of MDI test **********************************/
2500
2501 static void test_WM_SETREDRAW(HWND hwnd)
2502 {
2503     DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
2504
2505     flush_sequence();
2506
2507     SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
2508     ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
2509
2510     ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
2511     ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
2512
2513     flush_sequence();
2514     SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
2515     ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
2516
2517     ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
2518     ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
2519
2520     /* restore original WS_VISIBLE state */
2521     SetWindowLongA(hwnd, GWL_STYLE, style);
2522
2523     flush_sequence();
2524 }
2525
2526 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2527 {
2528     struct message msg;
2529
2530     trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2531
2532     switch (message)
2533     {
2534         case WM_WINDOWPOSCHANGING:
2535         case WM_WINDOWPOSCHANGED:
2536         {
2537             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
2538
2539             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
2540             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
2541                   winpos->hwnd, winpos->hwndInsertAfter,
2542                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
2543
2544             /* Log only documented flags, win2k uses 0x1000 and 0x2000
2545              * in the high word for internal purposes
2546              */
2547             wParam = winpos->flags & 0xffff;
2548             break;
2549         }
2550     }
2551
2552     msg.message = message;
2553     msg.flags = sent|wparam|lparam;
2554     msg.wParam = wParam;
2555     msg.lParam = lParam;
2556     add_message(&msg);
2557
2558     if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
2559     if (message == WM_TIMER) EndDialog( hwnd, 0 );
2560     return 0;
2561 }
2562
2563 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
2564 {
2565     DWORD style, exstyle;
2566     INT xmin, xmax;
2567     BOOL ret;
2568
2569     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
2570     style = GetWindowLongA(hwnd, GWL_STYLE);
2571     /* do not be confused by WS_DLGFRAME set */
2572     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
2573
2574     if (clear) ok(style & clear, "style %08lx should be set\n", clear);
2575     if (set) ok(!(style & set), "style %08lx should not be set\n", set);
2576
2577     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
2578     ok( ret, "SetScrollRange(%d) error %ld\n", ctl, GetLastError());
2579     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
2580         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
2581     else
2582         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
2583
2584     style = GetWindowLongA(hwnd, GWL_STYLE);
2585     if (set) ok(style & set, "style %08lx should be set\n", set);
2586     if (clear) ok(!(style & clear), "style %08lx should not be set\n", clear);
2587
2588     /* a subsequent call should do nothing */
2589     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
2590     ok( ret, "SetScrollRange(%d) error %ld\n", ctl, GetLastError());
2591     ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
2592
2593     xmin = 0xdeadbeef;
2594     xmax = 0xdeadbeef;
2595     trace("Ignore GetScrollRange error below if you are on Win9x\n");
2596     ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
2597     ok( ret, "GetScrollRange(%d) error %ld\n", ctl, GetLastError());
2598     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
2599     ok(xmin == min, "unexpected min scroll value %d\n", xmin);
2600     ok(xmax == max, "unexpected max scroll value %d\n", xmax);
2601 }
2602
2603 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
2604 {
2605     DWORD style, exstyle;
2606     SCROLLINFO si;
2607     BOOL ret;
2608
2609     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
2610     style = GetWindowLongA(hwnd, GWL_STYLE);
2611     /* do not be confused by WS_DLGFRAME set */
2612     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
2613
2614     if (clear) ok(style & clear, "style %08lx should be set\n", clear);
2615     if (set) ok(!(style & set), "style %08lx should not be set\n", set);
2616
2617     si.cbSize = sizeof(si);
2618     si.fMask = SIF_RANGE;
2619     si.nMin = min;
2620     si.nMax = max;
2621     SetScrollInfo(hwnd, ctl, &si, TRUE);
2622     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
2623         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
2624     else
2625         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
2626
2627     style = GetWindowLongA(hwnd, GWL_STYLE);
2628     if (set) ok(style & set, "style %08lx should be set\n", set);
2629     if (clear) ok(!(style & clear), "style %08lx should not be set\n", clear);
2630
2631     /* a subsequent call should do nothing */
2632     SetScrollInfo(hwnd, ctl, &si, TRUE);
2633     if (style & WS_HSCROLL)
2634         ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
2635     else if (style & WS_VSCROLL)
2636         ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
2637     else
2638         ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
2639
2640     si.fMask = SIF_PAGE;
2641     si.nPage = 5;
2642     SetScrollInfo(hwnd, ctl, &si, FALSE);
2643     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
2644
2645     si.fMask = SIF_POS;
2646     si.nPos = max - 1;
2647     SetScrollInfo(hwnd, ctl, &si, FALSE);
2648     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
2649
2650     si.fMask = SIF_RANGE;
2651     si.nMin = 0xdeadbeef;
2652     si.nMax = 0xdeadbeef;
2653     ret = GetScrollInfo(hwnd, ctl, &si);
2654     ok( ret, "GetScrollInfo error %ld\n", GetLastError());
2655     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
2656     ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
2657     ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
2658 }
2659
2660 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
2661 static void test_scroll_messages(HWND hwnd)
2662 {
2663     SCROLLINFO si;
2664     INT min, max;
2665     BOOL ret;
2666
2667     min = 0xdeadbeef;
2668     max = 0xdeadbeef;
2669     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
2670     ok( ret, "GetScrollRange error %ld\n", GetLastError());
2671     if (sequence->message != WmGetScrollRangeSeq[0].message)
2672         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
2673     /* values of min and max are undefined */
2674     flush_sequence();
2675
2676     ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
2677     ok( ret, "SetScrollRange error %ld\n", GetLastError());
2678     if (sequence->message != WmSetScrollRangeSeq[0].message)
2679         trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
2680     flush_sequence();
2681
2682     min = 0xdeadbeef;
2683     max = 0xdeadbeef;
2684     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
2685     ok( ret, "GetScrollRange error %ld\n", GetLastError());
2686     if (sequence->message != WmGetScrollRangeSeq[0].message)
2687         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
2688     /* values of min and max are undefined */
2689     flush_sequence();
2690
2691     si.cbSize = sizeof(si);
2692     si.fMask = SIF_RANGE;
2693     si.nMin = 20;
2694     si.nMax = 160;
2695     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
2696     if (sequence->message != WmSetScrollRangeSeq[0].message)
2697         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
2698     flush_sequence();
2699
2700     si.fMask = SIF_PAGE;
2701     si.nPage = 10;
2702     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
2703     if (sequence->message != WmSetScrollRangeSeq[0].message)
2704         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
2705     flush_sequence();
2706
2707     si.fMask = SIF_POS;
2708     si.nPos = 20;
2709     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
2710     if (sequence->message != WmSetScrollRangeSeq[0].message)
2711         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
2712     flush_sequence();
2713
2714     si.fMask = SIF_RANGE;
2715     si.nMin = 0xdeadbeef;
2716     si.nMax = 0xdeadbeef;
2717     ret = GetScrollInfo(hwnd, SB_CTL, &si);
2718     ok( ret, "GetScrollInfo error %ld\n", GetLastError());
2719     if (sequence->message != WmGetScrollInfoSeq[0].message)
2720         trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
2721     /* values of min and max are undefined */
2722     flush_sequence();
2723
2724     /* set WS_HSCROLL */
2725     test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
2726     /* clear WS_HSCROLL */
2727     test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
2728
2729     /* set WS_HSCROLL */
2730     test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
2731     /* clear WS_HSCROLL */
2732     test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
2733
2734     /* set WS_VSCROLL */
2735     test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
2736     /* clear WS_VSCROLL */
2737     test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
2738
2739     /* set WS_VSCROLL */
2740     test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
2741     /* clear WS_VSCROLL */
2742     test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
2743 }
2744
2745 static void test_showwindow(void)
2746 {
2747     HWND hwnd, hchild;
2748
2749     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
2750                            100, 100, 200, 200, 0, 0, 0, NULL);
2751     ok (hwnd != 0, "Failed to create overlapped window\n");
2752     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
2753                              0, 0, 10, 10, hwnd, 0, 0, NULL);
2754     ok (hchild != 0, "Failed to create child\n");
2755     flush_sequence();
2756
2757     /* ShowWindow( SW_SHOWNA) for invisible top level window */
2758     trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
2759     ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
2760     ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window.\n", TRUE);
2761     trace("done\n");
2762
2763     /* ShowWindow( SW_SHOWNA) for now visible top level window */
2764     trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
2765     ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
2766     ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window.\n", FALSE);
2767     trace("done\n");
2768     /* back to invisible */
2769     ShowWindow(hchild, SW_HIDE);
2770     ShowWindow(hwnd, SW_HIDE);
2771     flush_sequence();
2772     /* ShowWindow(SW_SHOWNA) with child and parent invisible */ 
2773     trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
2774     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
2775     ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent\n", TRUE);
2776     trace("done\n");
2777     /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */ 
2778     ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
2779     flush_sequence();
2780     trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
2781     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
2782     ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent\n", TRUE);
2783     trace("done\n");
2784     /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
2785     ShowWindow( hwnd, SW_SHOW);
2786     flush_sequence();
2787     trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
2788     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
2789     ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent\n", FALSE);
2790     trace("done\n");
2791
2792     /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
2793     ShowWindow( hchild, SW_HIDE);
2794     flush_sequence();
2795     trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
2796     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
2797     ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent\n", FALSE);
2798     trace("done\n");
2799
2800     DestroyWindow(hchild);
2801     DestroyWindow(hwnd);
2802     flush_sequence();
2803 }
2804
2805 /* test if we receive the right sequence of messages */
2806 static void test_messages(void)
2807 {
2808     HWND hwnd, hparent, hchild;
2809     HWND hchild2, hbutton;
2810     HMENU hmenu;
2811     MSG msg;
2812
2813     flush_sequence();
2814
2815     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
2816                            100, 100, 200, 200, 0, 0, 0, NULL);
2817     ok (hwnd != 0, "Failed to create overlapped window\n");
2818     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
2819
2820     /* test ShowWindow(SW_HIDE) on a newly created invisible window */
2821     ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
2822     ok_sequence(WmHideInvisibleOverlappedSeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
2823
2824     /* test WM_SETREDRAW on a not visible top level window */
2825     test_WM_SETREDRAW(hwnd);
2826
2827     SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
2828     ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
2829     ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
2830
2831     ok(GetActiveWindow() == hwnd, "window should be active\n");
2832     ok(GetFocus() == hwnd, "window should have input focus\n");
2833     ShowWindow(hwnd, SW_HIDE);
2834     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", TRUE);
2835     
2836     ShowWindow(hwnd, SW_SHOW);
2837     ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
2838
2839     ShowWindow(hwnd, SW_SHOW);
2840     ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
2841
2842     ok(GetActiveWindow() == hwnd, "window should be active\n");
2843     ok(GetFocus() == hwnd, "window should have input focus\n");
2844     SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
2845     ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
2846     ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
2847
2848     /* test WM_SETREDRAW on a visible top level window */
2849     ShowWindow(hwnd, SW_SHOW);
2850     test_WM_SETREDRAW(hwnd);
2851
2852     trace("testing scroll APIs on a visible top level window %p\n", hwnd);
2853     test_scroll_messages(hwnd);
2854
2855     /* test resizing and moving */
2856     SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE );
2857     ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
2858     SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE );
2859     ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
2860
2861     /* popups don't get WM_GETMINMAXINFO */
2862     SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
2863     SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
2864     flush_sequence();
2865     SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE );
2866     ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
2867
2868     DestroyWindow(hwnd);
2869     ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
2870
2871     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
2872                               100, 100, 200, 200, 0, 0, 0, NULL);
2873     ok (hparent != 0, "Failed to create parent window\n");
2874     flush_sequence();
2875
2876     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
2877                              0, 0, 10, 10, hparent, 0, 0, NULL);
2878     ok (hchild != 0, "Failed to create child window\n");
2879     ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", TRUE);
2880     DestroyWindow(hchild);
2881     flush_sequence();
2882
2883     /* visible child window with a caption */
2884     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
2885                              WS_CHILD | WS_VISIBLE | WS_CAPTION,
2886                              0, 0, 10, 10, hparent, 0, 0, NULL);
2887     ok (hchild != 0, "Failed to create child window\n");
2888     ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
2889
2890     trace("testing scroll APIs on a visible child window %p\n", hchild);
2891     test_scroll_messages(hchild);
2892
2893     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
2894     ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
2895
2896     DestroyWindow(hchild);
2897     flush_sequence();
2898
2899     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
2900                              0, 0, 10, 10, hparent, 0, 0, NULL);
2901     ok (hchild != 0, "Failed to create child window\n");
2902     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
2903     
2904     hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
2905                                100, 100, 50, 50, hparent, 0, 0, NULL);
2906     ok (hchild2 != 0, "Failed to create child2 window\n");
2907     flush_sequence();
2908
2909     hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
2910                               0, 100, 50, 50, hchild, 0, 0, NULL);
2911     ok (hbutton != 0, "Failed to create button window\n");
2912
2913     /* test WM_SETREDRAW on a not visible child window */
2914     test_WM_SETREDRAW(hchild);
2915
2916     ShowWindow(hchild, SW_SHOW);
2917     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
2918
2919     ShowWindow(hchild, SW_HIDE);
2920     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
2921
2922     ShowWindow(hchild, SW_SHOW);
2923     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
2924
2925     /* test WM_SETREDRAW on a visible child window */
2926     test_WM_SETREDRAW(hchild);
2927
2928     MoveWindow(hchild, 10, 10, 20, 20, TRUE);
2929     ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
2930
2931     ShowWindow(hchild, SW_HIDE);
2932     flush_sequence();
2933     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
2934     ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
2935
2936     ShowWindow(hchild, SW_HIDE);
2937     flush_sequence();
2938     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
2939     ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
2940
2941     /* DestroyWindow sequence below expects that a child has focus */
2942     SetFocus(hchild);
2943     flush_sequence();
2944
2945     DestroyWindow(hchild);
2946     ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
2947     DestroyWindow(hchild2);
2948     DestroyWindow(hbutton);
2949
2950     flush_sequence();
2951     hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
2952                              0, 0, 100, 100, hparent, 0, 0, NULL);
2953     ok (hchild != 0, "Failed to create child popup window\n");
2954     ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
2955     DestroyWindow(hchild);
2956
2957     /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
2958     flush_sequence();
2959     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
2960                              0, 0, 100, 100, hparent, 0, 0, NULL);
2961     ok (hchild != 0, "Failed to create popup window\n");
2962     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
2963     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
2964     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
2965     flush_sequence();
2966     ShowWindow(hchild, SW_SHOW);
2967     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
2968     flush_sequence();
2969     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
2970     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
2971     flush_sequence();
2972     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
2973     ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
2974     DestroyWindow(hchild);
2975
2976     /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
2977      * changes nothing in message sequences.
2978      */
2979     flush_sequence();
2980     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
2981                              0, 0, 100, 100, hparent, 0, 0, NULL);
2982     ok (hchild != 0, "Failed to create popup window\n");
2983     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
2984     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
2985     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
2986     flush_sequence();
2987     ShowWindow(hchild, SW_SHOW);
2988     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
2989     flush_sequence();
2990     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
2991     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
2992     DestroyWindow(hchild);
2993
2994     flush_sequence();
2995     hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
2996                            0, 0, 100, 100, hparent, 0, 0, NULL);
2997     ok(hwnd != 0, "Failed to create custom dialog window\n");
2998     ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
2999
3000     /*
3001     trace("testing scroll APIs on a visible dialog %p\n", hwnd);
3002     test_scroll_messages(hwnd);
3003     */
3004
3005     flush_sequence();
3006     after_end_dialog = 1;
3007     EndDialog( hwnd, 0 );
3008     ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
3009
3010     DestroyWindow(hwnd);
3011     after_end_dialog = 0;
3012
3013     hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP,
3014                            0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
3015     ok(hwnd != 0, "Failed to create custom dialog window\n");
3016     flush_sequence();
3017     trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
3018     ShowWindow(hwnd, SW_SHOW);
3019     ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
3020     DestroyWindow(hwnd);
3021
3022     flush_sequence();
3023     DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
3024     ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
3025
3026     /* test showing child with hidden parent */
3027     ShowWindow( hparent, SW_HIDE );
3028     flush_sequence();
3029
3030     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
3031                              0, 0, 10, 10, hparent, 0, 0, NULL);
3032     ok (hchild != 0, "Failed to create child window\n");
3033     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
3034
3035     ShowWindow( hchild, SW_SHOW );
3036     ok_sequence(WmShowChildInvisibleParentSeq, "ShowWindow:show child with invisible parent", TRUE);
3037     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
3038     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
3039
3040     ShowWindow( hchild, SW_HIDE );
3041     ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", TRUE);
3042     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
3043     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
3044
3045     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
3046     ok_sequence(WmShowChildInvisibleParentSeq_2, "SetWindowPos:show child with invisible parent", FALSE);
3047     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
3048     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
3049
3050     SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
3051     ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
3052     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
3053     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
3054
3055     DestroyWindow(hchild);
3056     DestroyWindow(hparent);
3057     flush_sequence();
3058
3059     /* Message sequence for SetMenu */
3060     ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a window without a menu\n");
3061     ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
3062
3063     hmenu = CreateMenu();
3064     ok (hmenu != 0, "Failed to create menu\n");
3065     ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
3066     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
3067                            100, 100, 200, 200, 0, hmenu, 0, NULL);
3068     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
3069     ok (SetMenu(hwnd, 0), "SetMenu\n");
3070     ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
3071     ok (SetMenu(hwnd, 0), "SetMenu\n");
3072     ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
3073     ShowWindow(hwnd, SW_SHOW);
3074     flush_sequence();
3075     ok (SetMenu(hwnd, 0), "SetMenu\n");
3076     ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", TRUE);
3077     ok (SetMenu(hwnd, hmenu), "SetMenu\n");
3078     ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", TRUE);
3079
3080     ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
3081     ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", TRUE);
3082
3083     DestroyWindow(hwnd);
3084     flush_sequence();
3085
3086     /* Message sequence for EnableWindow */
3087     hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
3088                               100, 100, 200, 200, 0, 0, 0, NULL);
3089     ok (hparent != 0, "Failed to create parent window\n");
3090     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
3091                              0, 0, 10, 10, hparent, 0, 0, NULL);
3092     ok (hchild != 0, "Failed to create child window\n");
3093
3094     SetFocus(hchild);
3095     flush_sequence();
3096
3097     EnableWindow(hparent, FALSE);
3098     ok_sequence(WmEnableWindowSeq, "EnableWindow", FALSE);
3099
3100     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3101     flush_sequence();
3102
3103     /* the following test causes an exception in user.exe under win9x */
3104     if (!PostMessageW( hparent, WM_USER, 0, 0 )) return;
3105     PostMessageW( hparent, WM_USER+1, 0, 0 );
3106     /* PeekMessage(NULL) fails, but still removes the message */
3107     SetLastError(0xdeadbeef);
3108     ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
3109     ok( GetLastError() == ERROR_NOACCESS, "last error is %ld\n", GetLastError() );
3110     ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
3111     ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
3112
3113     DestroyWindow(hchild);
3114     DestroyWindow(hparent);
3115     flush_sequence();
3116
3117     test_showwindow();
3118 }
3119
3120 /****************** button message test *************************/
3121 static const struct message WmSetFocusButtonSeq[] =
3122 {
3123     { HCBT_SETFOCUS, hook },
3124     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3125     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3126     { WM_SETFOCUS, sent|wparam, 0 },
3127     { WM_CTLCOLORBTN, sent|defwinproc },
3128     { 0 }
3129 };
3130 static const struct message WmKillFocusButtonSeq[] =
3131 {
3132     { HCBT_SETFOCUS, hook },
3133     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3134     { WM_KILLFOCUS, sent|wparam, 0 },
3135     { WM_CTLCOLORBTN, sent|defwinproc },
3136     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3137     { 0 }
3138 };
3139 static const struct message WmSetFocusStaticSeq[] =
3140 {
3141     { HCBT_SETFOCUS, hook },
3142     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3143     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3144     { WM_SETFOCUS, sent|wparam, 0 },
3145     { WM_CTLCOLORSTATIC, sent|defwinproc },
3146     { 0 }
3147 };
3148 static const struct message WmKillFocusStaticSeq[] =
3149 {
3150     { HCBT_SETFOCUS, hook },
3151     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3152     { WM_KILLFOCUS, sent|wparam, 0 },
3153     { WM_CTLCOLORSTATIC, sent|defwinproc },
3154     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3155     { 0 }
3156 };
3157 static const struct message WmLButtonDownSeq[] =
3158 {
3159     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
3160     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
3161     { HCBT_SETFOCUS, hook },
3162     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3163     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3164     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
3165     { WM_CTLCOLORBTN, sent|defwinproc },
3166     { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
3167     { WM_CTLCOLORBTN, sent|defwinproc },
3168     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3169     { 0 }
3170 };
3171 static const struct message WmLButtonUpSeq[] =
3172 {
3173     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
3174     { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
3175     { WM_CTLCOLORBTN, sent|defwinproc },
3176     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3177     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
3178     { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
3179     { 0 }
3180 };
3181
3182 static WNDPROC old_button_proc;
3183
3184 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3185 {
3186     static long defwndproc_counter = 0;
3187     LRESULT ret;
3188     struct message msg;
3189
3190     trace("button: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
3191
3192     msg.message = message;
3193     msg.flags = sent|wparam|lparam;
3194     if (defwndproc_counter) msg.flags |= defwinproc;
3195     msg.wParam = wParam;
3196     msg.lParam = lParam;
3197     add_message(&msg);
3198
3199     if (message == BM_SETSTATE)
3200         ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
3201
3202     defwndproc_counter++;
3203     ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
3204     defwndproc_counter--;
3205
3206     return ret;
3207 }
3208
3209 static void subclass_button(void)
3210 {
3211     WNDCLASSA cls;
3212
3213     if (!GetClassInfoA(0, "button", &cls)) assert(0);
3214
3215     old_button_proc = cls.lpfnWndProc;
3216
3217     cls.hInstance = GetModuleHandle(0);
3218     cls.lpfnWndProc = button_hook_proc;
3219     cls.lpszClassName = "my_button_class";
3220     if (!RegisterClassA(&cls)) assert(0);
3221 }
3222
3223 static void test_button_messages(void)
3224 {
3225     static const struct
3226     {
3227         DWORD style;
3228         DWORD dlg_code;
3229         const struct message *setfocus;
3230         const struct message *killfocus;
3231     } button[] = {
3232         { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
3233           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
3234         { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
3235           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
3236         { BS_CHECKBOX, DLGC_BUTTON,
3237           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
3238         { BS_AUTOCHECKBOX, DLGC_BUTTON,
3239           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
3240         { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
3241           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
3242         { BS_3STATE, DLGC_BUTTON,
3243           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
3244         { BS_AUTO3STATE, DLGC_BUTTON,
3245           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
3246         { BS_GROUPBOX, DLGC_STATIC,
3247           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
3248         { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
3249           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
3250         { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
3251           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
3252         { BS_OWNERDRAW, DLGC_BUTTON,
3253           WmSetFocusButtonSeq, WmKillFocusButtonSeq }
3254     };
3255     unsigned int i;
3256     HWND hwnd;
3257     DWORD dlg_code;
3258
3259     subclass_button();
3260
3261     for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
3262     {
3263         hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP,
3264                                0, 0, 50, 14, 0, 0, 0, NULL);
3265         ok(hwnd != 0, "Failed to create button window\n");
3266
3267         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
3268         ok(dlg_code == button[i].dlg_code, "%d: wrong dlg_code %08lx\n", i, dlg_code);
3269
3270         ShowWindow(hwnd, SW_SHOW);
3271         UpdateWindow(hwnd);
3272         SetFocus(0);
3273         flush_sequence();
3274
3275         trace("button style %08lx\n", button[i].style);
3276         SetFocus(hwnd);
3277         ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
3278
3279         SetFocus(0);
3280         ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
3281
3282         DestroyWindow(hwnd);
3283     }
3284
3285     hwnd = CreateWindowExA(0, "my_button_class", "test", BS_PUSHBUTTON | WS_POPUP | WS_VISIBLE,
3286                            0, 0, 50, 14, 0, 0, 0, NULL);
3287     ok(hwnd != 0, "Failed to create button window\n");
3288
3289     SetFocus(0);
3290     flush_sequence();
3291
3292     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
3293     ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
3294
3295     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
3296     ok_sequence(WmLButtonUpSeq, "WM_LBUTTONUP on a button", FALSE);
3297     DestroyWindow(hwnd);
3298 }
3299
3300 /************* painting message test ********************/
3301
3302 static void dump_region(HRGN hrgn)
3303 {
3304     DWORD i, size;
3305     RGNDATA *data = NULL;
3306     RECT *rect;
3307
3308     if (!hrgn)
3309     {
3310         printf( "null region\n" );
3311         return;
3312     }
3313     if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
3314     if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
3315     GetRegionData( hrgn, size, data );
3316     printf("%ld rects:", data->rdh.nCount );
3317     for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
3318         printf( " (%ld,%ld)-(%ld,%ld)", rect->left, rect->top, rect->right, rect->bottom );
3319     printf("\n");
3320     HeapFree( GetProcessHeap(), 0, data );
3321 }
3322
3323 static void check_update_rgn( HWND hwnd, HRGN hrgn )
3324 {
3325     INT ret;
3326     RECT r1, r2;
3327     HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
3328     HRGN update = CreateRectRgn( 0, 0, 0, 0 );
3329
3330     ret = GetUpdateRgn( hwnd, update, FALSE );
3331     ok( ret != ERROR, "GetUpdateRgn failed\n" );
3332     if (ret == NULLREGION)
3333     {
3334         ok( !hrgn, "Update region shouldn't be empty\n" );
3335     }
3336     else
3337     {
3338         if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
3339         {
3340             ok( 0, "Regions are different\n" );
3341             if (winetest_debug > 0)
3342             {
3343                 printf( "Update region: " );
3344                 dump_region( update );
3345                 printf( "Wanted region: " );
3346                 dump_region( hrgn );
3347             }
3348         }
3349     }
3350     GetRgnBox( update, &r1 );
3351     GetUpdateRect( hwnd, &r2, FALSE );
3352     ok( r1.left == r2.left && r1.top == r2.top && r1.right == r2.right && r1.bottom == r2.bottom,
3353         "Rectangles are different: %ld,%ld-%ld,%ld / %ld,%ld-%ld,%ld\n",
3354         r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom );
3355
3356     DeleteObject( tmp );
3357     DeleteObject( update );
3358 }
3359
3360 static const struct message WmInvalidateRgn[] = {
3361     { WM_NCPAINT, sent },
3362     { WM_GETTEXT, sent|defwinproc|optional },
3363     { 0 }
3364 };
3365
3366 static const struct message WmGetUpdateRect[] = {
3367     { WM_NCPAINT, sent },
3368     { WM_GETTEXT, sent|defwinproc|optional },
3369     { WM_PAINT, sent },
3370     { 0 }
3371 };
3372
3373 static const struct message WmInvalidateFull[] = {
3374     { WM_NCPAINT, sent|wparam, 1 },
3375     { WM_GETTEXT, sent|defwinproc|optional },
3376     { 0 }
3377 };
3378
3379 static const struct message WmInvalidateErase[] = {
3380     { WM_NCPAINT, sent|wparam, 1 },
3381     { WM_GETTEXT, sent|defwinproc|optional },
3382     { WM_ERASEBKGND, sent },
3383     { 0 }
3384 };
3385
3386 static const struct message WmInvalidatePaint[] = {
3387     { WM_PAINT, sent },
3388     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
3389     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
3390     { 0 }
3391 };
3392
3393 static const struct message WmInvalidateErasePaint[] = {
3394     { WM_PAINT, sent },
3395     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
3396     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
3397     { WM_ERASEBKGND, sent|beginpaint },
3398     { 0 }
3399 };
3400
3401 static const struct message WmInvalidateErasePaint2[] = {
3402     { WM_PAINT, sent },
3403     { WM_NCPAINT, sent|beginpaint },
3404     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
3405     { WM_ERASEBKGND, sent|beginpaint },
3406     { 0 }
3407 };
3408
3409 static const struct message WmErase[] = {
3410     { WM_ERASEBKGND, sent },
3411     { 0 }
3412 };
3413
3414 static const struct message WmPaint[] = {
3415     { WM_PAINT, sent },
3416     { 0 }
3417 };
3418
3419 static const struct message WmParentOnlyPaint[] = {
3420     { WM_PAINT, sent|parent },
3421     { 0 }
3422 };
3423
3424 static const struct message WmInvalidateParent[] = {
3425     { WM_NCPAINT, sent|parent },
3426     { WM_GETTEXT, sent|defwinproc|parent|optional },
3427     { WM_ERASEBKGND, sent|parent },
3428     { 0 }
3429 };
3430
3431 static const struct message WmInvalidateParentChild[] = {
3432     { WM_NCPAINT, sent|parent },
3433     { WM_GETTEXT, sent|defwinproc|parent|optional },
3434     { WM_ERASEBKGND, sent|parent },
3435     { WM_NCPAINT, sent },
3436     { WM_GETTEXT, sent|defwinproc|optional },
3437     { WM_ERASEBKGND, sent },
3438     { 0 }
3439 };
3440
3441 static const struct message WmInvalidateParentChild2[] = {
3442     { WM_ERASEBKGND, sent|parent },
3443     { WM_NCPAINT, sent },
3444     { WM_GETTEXT, sent|defwinproc|optional },
3445     { WM_ERASEBKGND, sent },
3446     { 0 }
3447 };
3448
3449 static const struct message WmParentPaint[] = {
3450     { WM_PAINT, sent|parent },
3451     { WM_PAINT, sent },
3452     { 0 }
3453 };
3454
3455 static const struct message WmParentPaintNc[] = {
3456     { WM_PAINT, sent|parent },
3457     { WM_PAINT, sent },
3458     { WM_NCPAINT, sent|beginpaint },
3459     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
3460     { WM_ERASEBKGND, sent|beginpaint },
3461     { 0 }
3462 };
3463
3464 static const struct message WmChildPaintNc[] = {
3465     { WM_PAINT, sent },
3466     { WM_NCPAINT, sent|beginpaint },
3467     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
3468     { WM_ERASEBKGND, sent|beginpaint },
3469     { 0 }
3470 };
3471
3472 static const struct message WmParentErasePaint[] = {
3473     { WM_PAINT, sent|parent },
3474     { WM_NCPAINT, sent|parent|beginpaint },
3475     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
3476     { WM_ERASEBKGND, sent|parent|beginpaint },
3477     { WM_PAINT, sent },
3478     { WM_NCPAINT, sent|beginpaint },
3479     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
3480     { WM_ERASEBKGND, sent|beginpaint },
3481     { 0 }
3482 };
3483
3484 static const struct message WmParentOnlyNcPaint[] = {
3485     { WM_PAINT, sent|parent },
3486     { WM_NCPAINT, sent|parent|beginpaint },
3487     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
3488     { 0 }
3489 };
3490
3491 static const struct message WmSetParentStyle[] = {
3492     { WM_STYLECHANGING, sent|parent },
3493     { WM_STYLECHANGED, sent|parent },
3494     { 0 }
3495 };
3496
3497 static void test_paint_messages(void)
3498 {
3499     RECT rect;
3500     POINT pt;
3501     MSG msg;
3502     HWND hparent, hchild;
3503     HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
3504     HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
3505     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
3506                                 100, 100, 200, 200, 0, 0, 0, NULL);
3507     ok (hwnd != 0, "Failed to create overlapped window\n");
3508
3509     ShowWindow( hwnd, SW_SHOW );
3510     UpdateWindow( hwnd );
3511
3512     /* try to flush pending X expose events */
3513     MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
3514     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3515
3516     check_update_rgn( hwnd, 0 );
3517     SetRectRgn( hrgn, 10, 10, 20, 20 );
3518     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
3519     check_update_rgn( hwnd, hrgn );
3520     SetRectRgn( hrgn2, 20, 20, 30, 30 );
3521     RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
3522     CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
3523     check_update_rgn( hwnd, hrgn );
3524     /* validate everything */
3525     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
3526     check_update_rgn( hwnd, 0 );
3527     /* now with frame */
3528     SetRectRgn( hrgn, -5, -5, 20, 20 );
3529
3530     /* flush pending messages */
3531     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3532
3533     flush_sequence();
3534     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
3535     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
3536
3537     SetRectRgn( hrgn, 0, 0, 20, 20 );  /* GetUpdateRgn clips to client area */
3538     check_update_rgn( hwnd, hrgn );
3539
3540     flush_sequence();
3541     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
3542     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
3543
3544     flush_sequence();
3545     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
3546     ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
3547
3548     GetClientRect( hwnd, &rect );
3549     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
3550     check_update_rgn( hwnd, hrgn );
3551
3552     flush_sequence();
3553     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
3554     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
3555
3556     flush_sequence();
3557     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
3558     ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
3559     check_update_rgn( hwnd, 0 );
3560
3561     flush_sequence();
3562     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
3563     ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
3564     check_update_rgn( hwnd, 0 );
3565
3566     flush_sequence();
3567     SetRectRgn( hrgn, 0, 0, 100, 100 );
3568     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
3569     SetRectRgn( hrgn, 0, 0, 50, 100 );
3570     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
3571     SetRectRgn( hrgn, 50, 0, 100, 100 );
3572     check_update_rgn( hwnd, hrgn );
3573     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
3574     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );  /* must not generate messages, everything is valid */
3575     check_update_rgn( hwnd, 0 );
3576
3577     flush_sequence();
3578     SetRectRgn( hrgn, 0, 0, 100, 100 );
3579     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
3580     SetRectRgn( hrgn, 0, 0, 100, 50 );
3581     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
3582     ok_sequence( WmErase, "Erase", FALSE );
3583     SetRectRgn( hrgn, 0, 50, 100, 100 );
3584     check_update_rgn( hwnd, hrgn );
3585
3586     flush_sequence();
3587     SetRectRgn( hrgn, 0, 0, 100, 100 );
3588     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
3589     SetRectRgn( hrgn, 0, 0, 50, 50 );
3590     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
3591     ok_sequence( WmPaint, "Paint", FALSE );
3592
3593     flush_sequence();
3594     SetRectRgn( hrgn, -4, -4, -2, -2 );
3595     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
3596     SetRectRgn( hrgn, -200, -200, -198, -198 );
3597     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
3598     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
3599
3600     flush_sequence();
3601     SetRectRgn( hrgn, -4, -4, -2, -2 );
3602     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
3603     SetRectRgn( hrgn, -4, -4, -3, -3 );
3604     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
3605     SetRectRgn( hrgn, 0, 0, 1, 1 );
3606     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
3607     ok_sequence( WmPaint, "Paint", FALSE );
3608
3609     flush_sequence();
3610     SetRectRgn( hrgn, -4, -4, -1, -1 );
3611     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
3612     RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
3613     /* make sure no WM_PAINT was generated */
3614     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3615     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
3616
3617     flush_sequence();
3618     SetRectRgn( hrgn, -4, -4, -1, -1 );
3619     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
3620     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
3621     {
3622         if (msg.hwnd == hwnd && msg.message == WM_PAINT)
3623         {
3624             /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
3625             INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
3626             ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
3627             ret = GetUpdateRect( hwnd, &rect, FALSE );
3628             ok( ret, "Invalid GetUpdateRect result %d\n", ret );
3629             /* this will send WM_NCPAINT and validate the non client area */
3630             ret = GetUpdateRect( hwnd, &rect, TRUE );
3631             ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
3632         }
3633         DispatchMessage( &msg );
3634     }
3635     ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
3636
3637     DestroyWindow( hwnd );
3638
3639     /* now test with a child window */
3640
3641     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
3642                               100, 100, 200, 200, 0, 0, 0, NULL);
3643     ok (hparent != 0, "Failed to create parent window\n");
3644
3645     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
3646                            10, 10, 100, 100, hparent, 0, 0, NULL);
3647     ok (hchild != 0, "Failed to create child window\n");
3648
3649     ShowWindow( hparent, SW_SHOW );
3650     UpdateWindow( hparent );
3651     UpdateWindow( hchild );
3652     /* try to flush pending X expose events */
3653     MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
3654     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3655
3656     flush_sequence();
3657     log_all_parent_messages++;
3658
3659     SetRect( &rect, 0, 0, 50, 50 );
3660     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
3661     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
3662     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
3663
3664     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
3665     pt.x = pt.y = 0;
3666     MapWindowPoints( hchild, hparent, &pt, 1 );
3667     SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
3668     check_update_rgn( hchild, hrgn );
3669     SetRectRgn( hrgn, 0, 0, 50, 50 );
3670     check_update_rgn( hparent, hrgn );
3671     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
3672     ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
3673     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
3674     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
3675
3676     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3677     ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
3678
3679     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
3680     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
3681     ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
3682     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
3683     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
3684
3685     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
3686     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
3687     ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
3688
3689     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
3690     flush_sequence();
3691     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
3692     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
3693     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
3694
3695     /* flush all paint messages */
3696     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3697     flush_sequence();
3698
3699     /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
3700     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
3701     SetRectRgn( hrgn, 0, 0, 50, 50 );
3702     check_update_rgn( hparent, hrgn );
3703     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
3704     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
3705     SetRectRgn( hrgn, 0, 0, 50, 50 );
3706     check_update_rgn( hparent, hrgn );
3707
3708     /* flush all paint messages */
3709     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3710     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
3711     flush_sequence();
3712
3713     /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
3714     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
3715     SetRectRgn( hrgn, 0, 0, 50, 50 );
3716     check_update_rgn( hparent, hrgn );
3717     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
3718     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
3719     SetRectRgn( hrgn2, 10, 10, 50, 50 );
3720     CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
3721     check_update_rgn( hparent, hrgn );
3722     /* flush all paint messages */
3723     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3724     flush_sequence();
3725
3726     /* same as above but parent gets completely validated */
3727     SetRect( &rect, 20, 20, 30, 30 );
3728     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
3729     SetRectRgn( hrgn, 20, 20, 30, 30 );
3730     check_update_rgn( hparent, hrgn );
3731     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
3732     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
3733     check_update_rgn( hparent, 0 );  /* no update region */
3734     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3735     ok_sequence( WmEmptySeq, "WmEmpty", FALSE );  /* and no paint messages */
3736
3737     /* make sure RDW_VALIDATE on child doesn't have the same effect */
3738     flush_sequence();
3739     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
3740     SetRectRgn( hrgn, 20, 20, 30, 30 );
3741     check_update_rgn( hparent, hrgn );
3742     RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
3743     SetRectRgn( hrgn, 20, 20, 30, 30 );
3744     check_update_rgn( hparent, hrgn );
3745
3746     /* same as above but normal WM_PAINT doesn't validate parent */
3747     flush_sequence();
3748     SetRect( &rect, 20, 20, 30, 30 );
3749     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
3750     SetRectRgn( hrgn, 20, 20, 30, 30 );
3751     check_update_rgn( hparent, hrgn );
3752     /* no WM_PAINT in child while parent still pending */
3753     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3754     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
3755     while (PeekMessage( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3756     ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
3757
3758     flush_sequence();
3759     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
3760     /* no WM_PAINT in child while parent still pending */
3761     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3762     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
3763     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
3764     /* now that parent is valid child should get WM_PAINT */
3765     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3766     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
3767     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3768     ok_sequence( WmEmptySeq, "No other message", FALSE );
3769
3770     /* same thing with WS_CLIPCHILDREN in parent */
3771     flush_sequence();
3772     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
3773     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
3774     /* changing style invalidates non client area, but we need to invalidate something else to see it */
3775     RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
3776     ok_sequence( WmEmptySeq, "No message", FALSE );
3777     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
3778     ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
3779
3780     flush_sequence();
3781     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
3782     SetRectRgn( hrgn, 20, 20, 30, 30 );
3783     check_update_rgn( hparent, hrgn );
3784     /* no WM_PAINT in child while parent still pending */
3785     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3786     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
3787     /* WM_PAINT in parent first */
3788     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3789     ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
3790
3791     /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
3792     flush_sequence();
3793     SetRect( &rect, 0, 0, 30, 30 );
3794     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
3795     SetRectRgn( hrgn, 0, 0, 30, 30 );
3796     check_update_rgn( hparent, hrgn );
3797     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3798     ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
3799
3800     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
3801     flush_sequence();
3802     SetRect( &rect, -10, 0, 30, 30 );
3803     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
3804     SetRect( &rect, 0, 0, 20, 20 );
3805     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
3806     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
3807     ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
3808
3809     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
3810     flush_sequence();
3811     SetRect( &rect, -10, 0, 30, 30 );
3812     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
3813     SetRect( &rect, 0, 0, 100, 100 );
3814     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
3815     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
3816     ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
3817     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
3818     ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
3819
3820     /* test RDW_INTERNALPAINT behavior */
3821
3822     flush_sequence();
3823     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
3824     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3825     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
3826
3827     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
3828     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3829     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
3830
3831     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
3832     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3833     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
3834
3835     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
3836     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
3837     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
3838     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3839     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
3840
3841     log_all_parent_messages--;
3842     DestroyWindow( hparent );
3843
3844     DeleteObject( hrgn );
3845     DeleteObject( hrgn2 );
3846 }
3847
3848 struct wnd_event
3849 {
3850     HWND hwnd;
3851     HANDLE event;
3852 };
3853
3854 static DWORD WINAPI thread_proc(void *param)
3855 {
3856     MSG msg;
3857     struct wnd_event *wnd_event = (struct wnd_event *)param;
3858
3859     wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
3860                                       100, 100, 200, 200, 0, 0, 0, NULL);
3861     ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
3862
3863     SetEvent(wnd_event->event);
3864
3865     while (GetMessage(&msg, 0, 0, 0))
3866     {
3867         TranslateMessage(&msg);
3868         DispatchMessage(&msg);
3869     }
3870
3871     ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
3872
3873     return 0;
3874 }
3875
3876 static void test_interthread_messages(void)
3877 {
3878     HANDLE hThread;
3879     DWORD tid;
3880     WNDPROC proc;
3881     MSG msg;
3882     char buf[256];
3883     int len, expected_len;
3884     struct wnd_event wnd_event;
3885     BOOL ret;
3886
3887     wnd_event.event = CreateEventW(NULL, 0, 0, NULL);
3888     if (!wnd_event.event)
3889     {
3890         trace("skipping interthread message test under win9x\n");
3891         return;
3892     }
3893
3894     hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
3895     ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError());
3896
3897     ok(WaitForSingleObject(wnd_event.event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
3898
3899     CloseHandle(wnd_event.event);
3900
3901     SetLastError(0xdeadbeef);
3902     ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeded\n");
3903     ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error code %ld\n", GetLastError());
3904
3905     proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
3906     ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %ld\n", GetLastError());
3907
3908     expected_len = lstrlenA("window caption text");
3909     memset(buf, 0, sizeof(buf));
3910     SetLastError(0xdeadbeef);
3911     len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
3912     ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %ld, len %d, expected len %d\n", GetLastError(), len, expected_len);
3913     ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
3914
3915     msg.hwnd = wnd_event.hwnd;
3916     msg.message = WM_GETTEXT;
3917     msg.wParam = sizeof(buf);
3918     msg.lParam = (LPARAM)buf;
3919     memset(buf, 0, sizeof(buf));
3920     SetLastError(0xdeadbeef);
3921     len = DispatchMessageA(&msg);
3922     ok(!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
3923        "DispatchMessageA(WM_GETTEXT) succeded on another thread window: ret %d, error %ld\n", len, GetLastError());
3924
3925     /* the following test causes an exception in user.exe under win9x */
3926     msg.hwnd = wnd_event.hwnd;
3927     msg.message = WM_TIMER;
3928     msg.wParam = 0;
3929     msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
3930     SetLastError(0xdeadbeef);
3931     len = DispatchMessageA(&msg);
3932     ok(!len && GetLastError() == 0xdeadbeef,
3933        "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %ld\n", len, GetLastError());
3934
3935     ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
3936     ok( ret, "PostMessageA(WM_QUIT) error %ld\n", GetLastError());
3937
3938     ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
3939     CloseHandle(hThread);
3940
3941     ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
3942 }
3943
3944
3945 static const struct message WmVkN[] = {
3946     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
3947     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
3948     { WM_CHAR, wparam|lparam, 'n', 1 },
3949     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
3950     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
3951     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
3952     { 0 }
3953 };
3954 static const struct message WmShiftVkN[] = {
3955     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
3956     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
3957     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
3958     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
3959     { WM_CHAR, wparam|lparam, 'N', 1 },
3960     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
3961     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
3962     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
3963     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
3964     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
3965     { 0 }
3966 };
3967 static const struct message WmCtrlVkN[] = {
3968     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
3969     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
3970     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
3971     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
3972     { WM_CHAR, wparam|lparam, 0x000e, 1 },
3973     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
3974     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
3975     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
3976     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
3977     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
3978     { 0 }
3979 };
3980 static const struct message WmCtrlVkN_2[] = {
3981     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
3982     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
3983     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
3984     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
3985     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
3986     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
3987     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
3988     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
3989     { 0 }
3990 };
3991 static const struct message WmAltVkN[] = {
3992     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
3993     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
3994     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
3995     { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
3996     { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
3997     { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
3998     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
3999     { HCBT_SYSCOMMAND, hook },
4000     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
4001     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
4002     { WM_INITMENU, sent|defwinproc },
4003     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
4004     { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
4005     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
4006     { WM_CAPTURECHANGED, sent|defwinproc },
4007     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
4008     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
4009     { WM_EXITMENULOOP, sent|defwinproc },
4010     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
4011     { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
4012     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
4013     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
4014     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
4015     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
4016     { 0 }
4017 };
4018 static const struct message WmAltVkN_2[] = {
4019     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
4020     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
4021     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
4022     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
4023     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
4024     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
4025     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
4026     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
4027     { 0 }
4028 };
4029 static const struct message WmCtrlAltVkN[] = {
4030     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
4031     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
4032     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
4033     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
4034     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
4035     { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
4036     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
4037     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
4038     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
4039     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
4040     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
4041     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
4042     { 0 }
4043 };
4044 static const struct message WmAltPressRelease[] = {
4045     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
4046     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
4047     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
4048     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
4049     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
4050     { HCBT_SYSCOMMAND, hook },
4051     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
4052     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
4053     { WM_INITMENU, sent|defwinproc },
4054     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
4055     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
4056     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
4057
4058     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
4059     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
4060     { WM_CAPTURECHANGED, sent|defwinproc },
4061     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
4062     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
4063     { WM_EXITMENULOOP, sent|defwinproc },
4064     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
4065     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
4066     { 0 }
4067 };
4068 static const struct message WmAltMouseButton[] = {
4069     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
4070     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
4071     { WM_MOUSEMOVE, wparam|optional, 0, 0 },
4072     { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
4073     { WM_LBUTTONDOWN, wparam, MK_LBUTTON, 0 },
4074     { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON, 0 },
4075     { WM_LBUTTONUP, wparam, 0, 0 },
4076     { WM_LBUTTONUP, sent|wparam, 0, 0 },
4077     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
4078     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
4079     { 0 }
4080 };
4081
4082 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
4083 {
4084     MSG msg;
4085
4086     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
4087     {
4088         struct message log_msg;
4089
4090         trace("accel: %p, %04x, %08x, %08lx\n", msg.hwnd, msg.message, msg.wParam, msg.lParam);
4091
4092         /* ignore some unwanted messages */
4093         if (msg.message == WM_MOUSEMOVE)
4094             continue;
4095
4096         log_msg.message = msg.message;
4097         log_msg.flags = wparam|lparam;
4098         log_msg.wParam = msg.wParam;
4099         log_msg.lParam = msg.lParam;
4100         add_message(&log_msg);
4101
4102         if (!hAccel || !TranslateAccelerator(hwnd, hAccel, &msg))
4103         {
4104             TranslateMessage(&msg);
4105             DispatchMessage(&msg);
4106         }
4107     }
4108 }
4109
4110 static void test_accelerators(void)
4111 {
4112     RECT rc;
4113     SHORT state;
4114     HACCEL hAccel;
4115     HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4116                                 100, 100, 200, 200, 0, 0, 0, NULL);
4117     BOOL ret;
4118
4119     assert(hwnd != 0);
4120     UpdateWindow(hwnd);
4121     SetFocus(hwnd);
4122     ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
4123
4124     state = GetKeyState(VK_SHIFT);
4125     ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
4126     state = GetKeyState(VK_CAPITAL);
4127     ok(state == 0, "wrong CapsLock state %04x\n", state);
4128
4129     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(1));
4130     assert(hAccel != 0);
4131
4132     pump_msg_loop(hwnd, 0);
4133     flush_sequence();
4134
4135     trace("testing VK_N press/release\n");
4136     flush_sequence();
4137     keybd_event('N', 0, 0, 0);
4138     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4139     pump_msg_loop(hwnd, hAccel);
4140     ok_sequence(WmVkN, "VK_N press/release", FALSE);
4141
4142     trace("testing Shift+VK_N press/release\n");
4143     flush_sequence();
4144     keybd_event(VK_SHIFT, 0, 0, 0);
4145     keybd_event('N', 0, 0, 0);
4146     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4147     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
4148     pump_msg_loop(hwnd, hAccel);
4149     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
4150
4151     trace("testing Ctrl+VK_N press/release\n");
4152     flush_sequence();
4153     keybd_event(VK_CONTROL, 0, 0, 0);
4154     keybd_event('N', 0, 0, 0);
4155     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4156     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
4157     pump_msg_loop(hwnd, hAccel);
4158     ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
4159
4160     trace("testing Alt+VK_N press/release\n");
4161     flush_sequence();
4162     keybd_event(VK_MENU, 0, 0, 0);
4163     keybd_event('N', 0, 0, 0);
4164     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4165     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
4166     pump_msg_loop(hwnd, hAccel);
4167     ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
4168
4169     trace("testing Ctrl+Alt+VK_N press/release\n");
4170     flush_sequence();
4171     keybd_event(VK_CONTROL, 0, 0, 0);
4172     keybd_event(VK_MENU, 0, 0, 0);
4173     keybd_event('N', 0, 0, 0);
4174     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4175     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
4176     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
4177     pump_msg_loop(hwnd, hAccel);
4178     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
4179
4180     ret = DestroyAcceleratorTable(hAccel);
4181     ok( ret, "DestroyAcceleratorTable error %ld\n", GetLastError());
4182
4183     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(2));
4184     assert(hAccel != 0);
4185
4186     trace("testing VK_N press/release\n");
4187     flush_sequence();
4188     keybd_event('N', 0, 0, 0);
4189     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4190     pump_msg_loop(hwnd, hAccel);
4191     ok_sequence(WmVkN, "VK_N press/release", FALSE);
4192
4193     trace("testing Shift+VK_N press/release\n");
4194     flush_sequence();
4195     keybd_event(VK_SHIFT, 0, 0, 0);
4196     keybd_event('N', 0, 0, 0);
4197     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4198     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
4199     pump_msg_loop(hwnd, hAccel);
4200     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
4201
4202     trace("testing Ctrl+VK_N press/release 2\n");
4203     flush_sequence();
4204     keybd_event(VK_CONTROL, 0, 0, 0);
4205     keybd_event('N', 0, 0, 0);
4206     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4207     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
4208     pump_msg_loop(hwnd, hAccel);
4209     ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
4210
4211     trace("testing Alt+VK_N press/release 2\n");
4212     flush_sequence();
4213     keybd_event(VK_MENU, 0, 0, 0);
4214     keybd_event('N', 0, 0, 0);
4215     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4216     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
4217     pump_msg_loop(hwnd, hAccel);
4218     ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
4219
4220     trace("testing Ctrl+Alt+VK_N press/release\n");
4221     flush_sequence();
4222     keybd_event(VK_CONTROL, 0, 0, 0);
4223     keybd_event(VK_MENU, 0, 0, 0);
4224     keybd_event('N', 0, 0, 0);
4225     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4226     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
4227     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
4228     pump_msg_loop(hwnd, hAccel);
4229     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
4230
4231     ret = DestroyAcceleratorTable(hAccel);
4232     ok( ret, "DestroyAcceleratorTable error %ld\n", GetLastError());
4233
4234     trace("testing Alt press/release\n");
4235     flush_sequence();
4236     keybd_event(VK_MENU, 0, 0, 0);
4237     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
4238     keybd_event(VK_MENU, 0, 0, 0);
4239     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
4240     pump_msg_loop(hwnd, 0);
4241     /* this test doesn't pass in Wine for managed windows */
4242     ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
4243
4244     trace("testing Alt+MouseButton press/release\n");
4245     /* first, move mouse pointer inside of the window client area */
4246     GetClientRect(hwnd, &rc);
4247     MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
4248     rc.left += (rc.right - rc.left)/2;
4249     rc.top += (rc.bottom - rc.top)/2;
4250     SetCursorPos(rc.left, rc.top);
4251
4252     pump_msg_loop(hwnd, 0);
4253     flush_sequence();
4254     keybd_event(VK_MENU, 0, 0, 0);
4255     mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
4256     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
4257     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
4258     pump_msg_loop(hwnd, 0);
4259     ok_sequence(WmAltMouseButton, "Alt+MouseButton press/release", FALSE);
4260
4261     DestroyWindow(hwnd);
4262 }
4263
4264 /************* window procedures ********************/
4265
4266 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4267 {
4268     static long defwndproc_counter = 0;
4269     static long beginpaint_counter = 0;
4270     LRESULT ret;
4271     struct message msg;
4272
4273     trace("%p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
4274
4275     switch (message)
4276     {
4277         /* test_accelerators() depends on this */
4278         case WM_NCHITTEST:
4279             return HTCLIENT;
4280     
4281         /* ignore */
4282         case WM_MOUSEMOVE:
4283         case WM_SETCURSOR:
4284             return 0;
4285
4286         case WM_WINDOWPOSCHANGING:
4287         case WM_WINDOWPOSCHANGED:
4288         {
4289             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
4290
4291             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
4292             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
4293                   winpos->hwnd, winpos->hwndInsertAfter,
4294                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
4295
4296             /* Log only documented flags, win2k uses 0x1000 and 0x2000
4297              * in the high word for internal purposes
4298              */
4299             wParam = winpos->flags & 0xffff;
4300             break;
4301         }
4302     }
4303
4304     msg.message = message;
4305     msg.flags = sent|wparam|lparam;
4306     if (defwndproc_counter) msg.flags |= defwinproc;
4307     if (beginpaint_counter) msg.flags |= beginpaint;
4308     msg.wParam = wParam;
4309     msg.lParam = lParam;
4310     add_message(&msg);
4311
4312     if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
4313     {
4314         HWND parent = GetParent(hwnd);
4315         RECT rc;
4316         MINMAXINFO *minmax = (MINMAXINFO *)lParam;
4317
4318         GetClientRect(parent, &rc);
4319         trace("parent %p client size = (%ld x %ld)\n", parent, rc.right, rc.bottom);
4320
4321         trace("ptReserved = (%ld,%ld)\n"
4322               "ptMaxSize = (%ld,%ld)\n"
4323               "ptMaxPosition = (%ld,%ld)\n"
4324               "ptMinTrackSize = (%ld,%ld)\n"
4325               "ptMaxTrackSize = (%ld,%ld)\n",
4326               minmax->ptReserved.x, minmax->ptReserved.y,
4327               minmax->ptMaxSize.x, minmax->ptMaxSize.y,
4328               minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
4329               minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
4330               minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
4331
4332         ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %ld != %ld\n",
4333            minmax->ptMaxSize.x, rc.right);
4334         ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %ld != %ld\n",
4335            minmax->ptMaxSize.y, rc.bottom);
4336     }
4337
4338     if (message == WM_PAINT)
4339     {
4340         PAINTSTRUCT ps;
4341         beginpaint_counter++;
4342         BeginPaint( hwnd, &ps );
4343         beginpaint_counter--;
4344         EndPaint( hwnd, &ps );
4345         return 0;
4346     }
4347
4348     defwndproc_counter++;
4349     ret = DefWindowProcA(hwnd, message, wParam, lParam);
4350     defwndproc_counter--;
4351
4352     return ret;
4353 }
4354
4355 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4356 {
4357     static long defwndproc_counter = 0;
4358     LRESULT ret;
4359     struct message msg;
4360
4361     trace("popup: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
4362
4363     msg.message = message;
4364     msg.flags = sent|wparam|lparam;
4365     if (defwndproc_counter) msg.flags |= defwinproc;
4366     msg.wParam = wParam;
4367     msg.lParam = lParam;
4368     add_message(&msg);
4369
4370     if (message == WM_CREATE)
4371     {
4372         DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
4373         SetWindowLongA(hwnd, GWL_STYLE, style);
4374     }
4375
4376     defwndproc_counter++;
4377     ret = DefWindowProcA(hwnd, message, wParam, lParam);
4378     defwndproc_counter--;
4379
4380     return ret;
4381 }
4382
4383 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4384 {
4385     static long defwndproc_counter = 0;
4386     static long beginpaint_counter = 0;
4387     LRESULT ret;
4388     struct message msg;
4389
4390     trace("parent: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
4391
4392     if (log_all_parent_messages ||
4393         message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
4394         message == WM_SETFOCUS || message == WM_KILLFOCUS ||
4395         message == WM_ENABLE || message == WM_ENTERIDLE ||
4396         message == WM_IME_SETCONTEXT)
4397     {
4398         msg.message = message;
4399         msg.flags = sent|parent|wparam|lparam;
4400         if (defwndproc_counter) msg.flags |= defwinproc;
4401         if (beginpaint_counter) msg.flags |= beginpaint;
4402         msg.wParam = wParam;
4403         msg.lParam = lParam;
4404         add_message(&msg);
4405     }
4406
4407     if (message == WM_PAINT)
4408     {
4409         PAINTSTRUCT ps;
4410         beginpaint_counter++;
4411         BeginPaint( hwnd, &ps );
4412         beginpaint_counter--;
4413         EndPaint( hwnd, &ps );
4414         return 0;
4415     }
4416
4417     defwndproc_counter++;
4418     ret = DefWindowProcA(hwnd, message, wParam, lParam);
4419     defwndproc_counter--;
4420
4421     return ret;
4422 }
4423
4424 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4425 {
4426     static long defwndproc_counter = 0;
4427     LRESULT ret;
4428     struct message msg;
4429
4430     trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
4431
4432     DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
4433     ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
4434     if (after_end_dialog)
4435         ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
4436     else
4437         ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
4438
4439     switch (message)
4440     {
4441         case WM_WINDOWPOSCHANGING:
4442         case WM_WINDOWPOSCHANGED:
4443         {
4444             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
4445
4446             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
4447             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
4448                   winpos->hwnd, winpos->hwndInsertAfter,
4449                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
4450
4451             /* Log only documented flags, win2k uses 0x1000 and 0x2000
4452              * in the high word for internal purposes
4453              */
4454             wParam = winpos->flags & 0xffff;
4455             break;
4456         }
4457     }
4458
4459     msg.message = message;
4460     msg.flags = sent|wparam|lparam;
4461     if (defwndproc_counter) msg.flags |= defwinproc;
4462     msg.wParam = wParam;
4463     msg.lParam = lParam;
4464     add_message(&msg);
4465
4466     defwndproc_counter++;
4467     ret = DefDlgProcA(hwnd, message, wParam, lParam);
4468     defwndproc_counter--;
4469
4470     return ret;
4471 }
4472
4473 static BOOL RegisterWindowClasses(void)
4474 {
4475     WNDCLASSA cls;
4476
4477     cls.style = 0;
4478     cls.lpfnWndProc = MsgCheckProcA;
4479     cls.cbClsExtra = 0;
4480     cls.cbWndExtra = 0;
4481     cls.hInstance = GetModuleHandleA(0);
4482     cls.hIcon = 0;
4483     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
4484     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
4485     cls.lpszMenuName = NULL;
4486     cls.lpszClassName = "TestWindowClass";
4487     if(!RegisterClassA(&cls)) return FALSE;
4488
4489     cls.lpfnWndProc = PopupMsgCheckProcA;
4490     cls.lpszClassName = "TestPopupClass";
4491     if(!RegisterClassA(&cls)) return FALSE;
4492
4493     cls.lpfnWndProc = ParentMsgCheckProcA;
4494     cls.lpszClassName = "TestParentClass";
4495     if(!RegisterClassA(&cls)) return FALSE;
4496
4497     cls.lpfnWndProc = DefWindowProcA;
4498     cls.lpszClassName = "SimpleWindowClass";
4499     if(!RegisterClassA(&cls)) return FALSE;
4500
4501     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
4502     cls.style = 0;
4503     cls.hInstance = GetModuleHandleA(0);
4504     cls.hbrBackground = 0;
4505     cls.lpfnWndProc = TestDlgProcA;
4506     cls.lpszClassName = "TestDialogClass";
4507     if(!RegisterClassA(&cls)) return FALSE;
4508
4509     return TRUE;
4510 }
4511
4512 static HHOOK hCBT_hook;
4513
4514 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
4515
4516     char buf[256];
4517
4518     trace("CBT: %d, %08x, %08lx\n", nCode, wParam, lParam);
4519
4520     if (nCode == HCBT_SYSCOMMAND)
4521     {
4522         struct message msg;
4523
4524         msg.message = nCode;
4525         msg.flags = hook;
4526         msg.wParam = wParam;
4527         msg.lParam = lParam;
4528         add_message(&msg);
4529
4530         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
4531     }
4532
4533     /* Log also SetFocus(0) calls */
4534     if (!wParam) wParam = lParam;
4535
4536     if (GetClassNameA((HWND)wParam, buf, sizeof(buf)))
4537     {
4538         if (!strcmp(buf, "TestWindowClass") ||
4539             !strcmp(buf, "TestParentClass") ||
4540             !strcmp(buf, "TestPopupClass") ||
4541             !strcmp(buf, "SimpleWindowClass") ||
4542             !strcmp(buf, "TestDialogClass") ||
4543             !strcmp(buf, "MDI_frame_class") ||
4544             !strcmp(buf, "MDI_client_class") ||
4545             !strcmp(buf, "MDI_child_class") ||
4546             !strcmp(buf, "my_button_class") ||
4547             !strcmp(buf, "#32770"))
4548         {
4549             struct message msg;
4550
4551             msg.message = nCode;
4552             msg.flags = hook|wparam|lparam;
4553             msg.wParam = wParam;
4554             msg.lParam = lParam;
4555             add_message(&msg);
4556         }
4557     }
4558     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
4559 }
4560
4561 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
4562                                     DWORD event,
4563                                     HWND hwnd,
4564                                     LONG object_id,
4565                                     LONG child_id,
4566                                     DWORD thread_id,
4567                                     DWORD event_time)
4568 {
4569     char buf[256];
4570
4571     trace("WEH:%p,event %08lx,hwnd %p,obj %08lx,id %08lx,thread %08lx,time %08lx\n",
4572            hevent, event, hwnd, object_id, child_id, thread_id, event_time);
4573
4574     /* ignore mouse cursor events */
4575     if (object_id == OBJID_CURSOR) return;
4576
4577     if (!hwnd || GetClassNameA(hwnd, buf, sizeof(buf)))
4578     {
4579         if (!hwnd ||
4580             !strcmp(buf, "TestWindowClass") ||
4581             !strcmp(buf, "TestParentClass") ||
4582             !strcmp(buf, "TestPopupClass") ||
4583             !strcmp(buf, "SimpleWindowClass") ||
4584             !strcmp(buf, "TestDialogClass") ||
4585             !strcmp(buf, "MDI_frame_class") ||
4586             !strcmp(buf, "MDI_client_class") ||
4587             !strcmp(buf, "MDI_child_class") ||
4588             !strcmp(buf, "my_button_class") ||
4589             !strcmp(buf, "#32770"))
4590         {
4591             struct message msg;
4592
4593             msg.message = event;
4594             msg.flags = winevent_hook|wparam|lparam;
4595             msg.wParam = object_id;
4596             msg.lParam = child_id;
4597             add_message(&msg);
4598         }
4599     }
4600 }
4601
4602 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
4603 static const WCHAR wszAnsi[] = {'U',0};
4604
4605 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
4606 {
4607     switch (uMsg)
4608     {
4609     case CB_FINDSTRINGEXACT:
4610         trace("String: %p\n", (LPCWSTR)lParam);
4611         if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
4612             return 1;
4613         if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
4614             return 0;
4615         return -1;
4616     }
4617     return DefWindowProcW(hwnd, uMsg, wParam, lParam);
4618 }
4619
4620 static void test_message_conversion(void)
4621 {
4622     static const WCHAR wszMsgConversionClass[] =
4623         {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
4624     WNDCLASSW cls;
4625     LRESULT lRes;
4626     HWND hwnd;
4627     WNDPROC wndproc;
4628
4629     cls.style = 0;
4630     cls.lpfnWndProc = MsgConversionProcW;
4631     cls.cbClsExtra = 0;
4632     cls.cbWndExtra = 0;
4633     cls.hInstance = GetModuleHandleW(NULL);
4634     cls.hIcon = NULL;
4635     cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
4636     cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
4637     cls.lpszMenuName = NULL;
4638     cls.lpszClassName = wszMsgConversionClass;
4639     /* this call will fail on Win9x, but that doesn't matter as this test is
4640      * meaningless on those platforms */
4641     if(!RegisterClassW(&cls)) return;
4642
4643     hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
4644                            100, 100, 200, 200, 0, 0, 0, NULL);
4645     ok(hwnd != NULL, "Window creation failed\n");
4646
4647     /* {W, A} -> A */
4648
4649     wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
4650     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4651     ok(lRes == 0, "String should have been converted\n");
4652     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4653     ok(lRes == 1, "String shouldn't have been converted\n");
4654
4655     /* {W, A} -> W */
4656
4657     wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
4658     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4659     ok(lRes == 1, "String shouldn't have been converted\n");
4660     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4661     ok(lRes == 1, "String shouldn't have been converted\n");
4662
4663     /* Synchronous messages */
4664
4665     lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4666     ok(lRes == 0, "String should have been converted\n");
4667     lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4668     ok(lRes == 1, "String shouldn't have been converted\n");
4669
4670     /* Asynchronous messages */
4671
4672     SetLastError(0);
4673     lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4674     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4675         "PostMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4676     SetLastError(0);
4677     lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4678     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4679         "PostMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4680     SetLastError(0);
4681     lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4682     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4683         "PosThreadtMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4684     SetLastError(0);
4685     lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4686     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4687         "PosThreadtMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4688     SetLastError(0);
4689     lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4690     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4691         "SendNotifyMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4692     SetLastError(0);
4693     lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4694     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4695         "SendNotifyMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4696     SetLastError(0);
4697     lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
4698     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4699         "SendMessageCallback on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4700     SetLastError(0);
4701     lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
4702     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4703         "SendMessageCallback on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4704 }
4705
4706 typedef struct _thread_info
4707 {
4708     HWND hWnd;
4709     HANDLE handles[2];
4710     DWORD id;
4711 } thread_info;
4712
4713 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT id, DWORD dwTime)
4714 {
4715 }
4716
4717 #define TIMER_ID  0x19
4718
4719 static DWORD WINAPI timer_thread_proc(LPVOID x)
4720 {
4721     thread_info *info = x;
4722     DWORD r;
4723
4724     r = KillTimer(info->hWnd, 0x19);
4725     ok(r,"KillTimer failed in thread\n");
4726     r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
4727     ok(r,"SetTimer failed in thread\n");
4728     ok(r==TIMER_ID,"SetTimer id different\n");
4729     r = SetEvent(info->handles[0]);
4730     ok(r,"SetEvent failed in thread\n");
4731     return 0;
4732 }
4733
4734 static void test_timers(void)
4735 {
4736     thread_info info;
4737     DWORD id;
4738
4739     info.hWnd = CreateWindow ("TestWindowClass", NULL,
4740        WS_OVERLAPPEDWINDOW ,
4741        CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4742        NULL, NULL, 0);
4743
4744     info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
4745     ok(info.id, "SetTimer failed\n");
4746     ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
4747     info.handles[0] = CreateEvent(NULL,0,0,NULL);
4748     info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
4749
4750     WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
4751
4752     WaitForSingleObject(info.handles[1], INFINITE);
4753
4754     ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
4755
4756     ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
4757 }
4758
4759 /* Various win events with arbitrary parameters */
4760 static const struct message WmWinEventsSeq[] = {
4761     { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
4762     { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
4763     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
4764     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
4765     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
4766     { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
4767     { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
4768     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
4769     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
4770     /* our win event hook ignores OBJID_CURSOR events */
4771     /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
4772     { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
4773     { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
4774     { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
4775     { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
4776     { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
4777     { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
4778     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
4779     { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
4780     { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
4781     { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
4782     { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
4783     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
4784     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
4785     { 0 }
4786 };
4787
4788 static void test_winevents(void)
4789 {
4790     HWND hwnd;
4791     UINT i;
4792     const struct message *events = WmWinEventsSeq;
4793     HMODULE user32 = GetModuleHandleA("user32.dll");
4794     FARPROC pNotifyWinEvent = GetProcAddress(user32, "NotifyWinEvent");
4795
4796     if (!pNotifyWinEvent) return;
4797
4798     hwnd = CreateWindow ("TestWindowClass", NULL,
4799                         WS_OVERLAPPEDWINDOW,
4800                         CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4801                         NULL, NULL, 0);
4802     assert(hwnd);
4803
4804     flush_sequence();
4805
4806     /* Windows ignores events with hwnd == 0 */
4807     SetLastError(0xdeadbeef);
4808     pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
4809     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
4810        GetLastError() == 0xdeadbeef, /* Win9x */
4811        "unexpected error %ld\n", GetLastError());
4812     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
4813
4814     for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++)
4815         pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
4816
4817     ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
4818     ok(DestroyWindow(hwnd), "failed to destroy window\n");
4819 }
4820
4821 START_TEST(msg)
4822 {
4823     HMODULE user32 = GetModuleHandleA("user32.dll");
4824     FARPROC pSetWinEventHook = 0;/*GetProcAddress(user32, "SetWinEventHook");*/
4825     FARPROC pUnhookWinEvent = 0;/*GetProcAddress(user32, "UnhookWinEvent");*/
4826     FARPROC pIsWinEventHookInstalled = GetProcAddress(user32, "IsWinEventHookInstalled");
4827
4828     if (!RegisterWindowClasses()) assert(0);
4829
4830     if (pSetWinEventHook)
4831     {
4832         UINT event;
4833         hEvent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
4834                                                       GetModuleHandleA(0),
4835                                                       win_event_proc,
4836                                                       GetCurrentProcessId(),
4837                                                       0,
4838                                                       WINEVENT_INCONTEXT);
4839         assert(hEvent_hook);
4840
4841         if (pIsWinEventHookInstalled)
4842         {
4843             for (event = EVENT_MIN; event <= EVENT_MAX; event++)
4844                 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
4845         }
4846     }
4847
4848     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
4849     assert(hCBT_hook);
4850
4851     test_messages();
4852     test_mdi_messages();
4853     test_button_messages();
4854     test_paint_messages();
4855     test_interthread_messages();
4856     test_message_conversion();
4857     test_accelerators();
4858     test_timers();
4859     test_winevents();
4860
4861     UnhookWindowsHookEx(hCBT_hook);
4862     if (pUnhookWinEvent)
4863     {
4864         ok(pUnhookWinEvent(hEvent_hook), "UnhookWinEvent error %ld\n", GetLastError());
4865         SetLastError(0xdeadbeef);
4866         ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
4867         ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
4868            GetLastError() == 0xdeadbeef, /* Win9x */
4869            "unexpected error %ld\n", GetLastError());
4870     }
4871 }