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