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