Reverse the order for deleting the items in resetcontent to correctly
[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 WmAltPressRelease[] = {
4050     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
4051     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
4052     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
4053     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
4054     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
4055     { HCBT_SYSCOMMAND, hook },
4056     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
4057     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
4058     { WM_INITMENU, sent|defwinproc },
4059     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
4060     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
4061     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
4062
4063     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
4064     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
4065     { WM_CAPTURECHANGED, sent|defwinproc },
4066     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
4067     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
4068     { WM_EXITMENULOOP, sent|defwinproc },
4069     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
4070     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
4071     { 0 }
4072 };
4073 static const struct message WmAltMouseButton[] = {
4074     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
4075     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
4076     { WM_MOUSEMOVE, wparam|optional, 0, 0 },
4077     { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
4078     { WM_LBUTTONDOWN, wparam, MK_LBUTTON, 0 },
4079     { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON, 0 },
4080     { WM_LBUTTONUP, wparam, 0, 0 },
4081     { WM_LBUTTONUP, sent|wparam, 0, 0 },
4082     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
4083     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
4084     { 0 }
4085 };
4086
4087 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
4088 {
4089     MSG msg;
4090
4091     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
4092     {
4093         struct message log_msg;
4094
4095         trace("accel: %p, %04x, %08x, %08lx\n", msg.hwnd, msg.message, msg.wParam, msg.lParam);
4096
4097         /* ignore some unwanted messages */
4098         if (msg.message == WM_MOUSEMOVE ||
4099             msg.message == WM_DEVICECHANGE)
4100             continue;
4101
4102         log_msg.message = msg.message;
4103         log_msg.flags = wparam|lparam;
4104         log_msg.wParam = msg.wParam;
4105         log_msg.lParam = msg.lParam;
4106         add_message(&log_msg);
4107
4108         if (!hAccel || !TranslateAccelerator(hwnd, hAccel, &msg))
4109         {
4110             TranslateMessage(&msg);
4111             DispatchMessage(&msg);
4112         }
4113     }
4114 }
4115
4116 static void test_accelerators(void)
4117 {
4118     RECT rc;
4119     SHORT state;
4120     HACCEL hAccel;
4121     HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4122                                 100, 100, 200, 200, 0, 0, 0, NULL);
4123     BOOL ret;
4124
4125     assert(hwnd != 0);
4126     UpdateWindow(hwnd);
4127     SetFocus(hwnd);
4128     ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
4129
4130     state = GetKeyState(VK_SHIFT);
4131     ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
4132     state = GetKeyState(VK_CAPITAL);
4133     ok(state == 0, "wrong CapsLock state %04x\n", state);
4134
4135     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(1));
4136     assert(hAccel != 0);
4137
4138     pump_msg_loop(hwnd, 0);
4139     flush_sequence();
4140
4141     trace("testing VK_N press/release\n");
4142     flush_sequence();
4143     keybd_event('N', 0, 0, 0);
4144     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4145     pump_msg_loop(hwnd, hAccel);
4146     ok_sequence(WmVkN, "VK_N press/release", FALSE);
4147
4148     trace("testing Shift+VK_N press/release\n");
4149     flush_sequence();
4150     keybd_event(VK_SHIFT, 0, 0, 0);
4151     keybd_event('N', 0, 0, 0);
4152     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4153     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
4154     pump_msg_loop(hwnd, hAccel);
4155     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
4156
4157     trace("testing Ctrl+VK_N press/release\n");
4158     flush_sequence();
4159     keybd_event(VK_CONTROL, 0, 0, 0);
4160     keybd_event('N', 0, 0, 0);
4161     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4162     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
4163     pump_msg_loop(hwnd, hAccel);
4164     ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
4165
4166     trace("testing Alt+VK_N press/release\n");
4167     flush_sequence();
4168     keybd_event(VK_MENU, 0, 0, 0);
4169     keybd_event('N', 0, 0, 0);
4170     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4171     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
4172     pump_msg_loop(hwnd, hAccel);
4173     ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
4174
4175     trace("testing Ctrl+Alt+VK_N press/release\n");
4176     flush_sequence();
4177     keybd_event(VK_CONTROL, 0, 0, 0);
4178     keybd_event(VK_MENU, 0, 0, 0);
4179     keybd_event('N', 0, 0, 0);
4180     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4181     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
4182     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
4183     pump_msg_loop(hwnd, hAccel);
4184     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
4185
4186     ret = DestroyAcceleratorTable(hAccel);
4187     ok( ret, "DestroyAcceleratorTable error %ld\n", GetLastError());
4188
4189     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(2));
4190     assert(hAccel != 0);
4191
4192     trace("testing VK_N press/release\n");
4193     flush_sequence();
4194     keybd_event('N', 0, 0, 0);
4195     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4196     pump_msg_loop(hwnd, hAccel);
4197     ok_sequence(WmVkN, "VK_N press/release", FALSE);
4198
4199     trace("testing Shift+VK_N press/release\n");
4200     flush_sequence();
4201     keybd_event(VK_SHIFT, 0, 0, 0);
4202     keybd_event('N', 0, 0, 0);
4203     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4204     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
4205     pump_msg_loop(hwnd, hAccel);
4206     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
4207
4208     trace("testing Ctrl+VK_N press/release 2\n");
4209     flush_sequence();
4210     keybd_event(VK_CONTROL, 0, 0, 0);
4211     keybd_event('N', 0, 0, 0);
4212     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4213     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
4214     pump_msg_loop(hwnd, hAccel);
4215     ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
4216
4217     trace("testing Alt+VK_N press/release 2\n");
4218     flush_sequence();
4219     keybd_event(VK_MENU, 0, 0, 0);
4220     keybd_event('N', 0, 0, 0);
4221     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4222     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
4223     pump_msg_loop(hwnd, hAccel);
4224     ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
4225
4226     trace("testing Ctrl+Alt+VK_N press/release\n");
4227     flush_sequence();
4228     keybd_event(VK_CONTROL, 0, 0, 0);
4229     keybd_event(VK_MENU, 0, 0, 0);
4230     keybd_event('N', 0, 0, 0);
4231     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4232     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
4233     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
4234     pump_msg_loop(hwnd, hAccel);
4235     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
4236
4237     ret = DestroyAcceleratorTable(hAccel);
4238     ok( ret, "DestroyAcceleratorTable error %ld\n", GetLastError());
4239
4240     trace("testing Alt press/release\n");
4241     flush_sequence();
4242     keybd_event(VK_MENU, 0, 0, 0);
4243     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
4244     keybd_event(VK_MENU, 0, 0, 0);
4245     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
4246     pump_msg_loop(hwnd, 0);
4247     /* this test doesn't pass in Wine for managed windows */
4248     ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
4249
4250     trace("testing Alt+MouseButton press/release\n");
4251     /* first, move mouse pointer inside of the window client area */
4252     GetClientRect(hwnd, &rc);
4253     MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
4254     rc.left += (rc.right - rc.left)/2;
4255     rc.top += (rc.bottom - rc.top)/2;
4256     SetCursorPos(rc.left, rc.top);
4257
4258     pump_msg_loop(hwnd, 0);
4259     flush_sequence();
4260     keybd_event(VK_MENU, 0, 0, 0);
4261     mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
4262     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
4263     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
4264     pump_msg_loop(hwnd, 0);
4265     ok_sequence(WmAltMouseButton, "Alt+MouseButton press/release", FALSE);
4266
4267     DestroyWindow(hwnd);
4268 }
4269
4270 /************* window procedures ********************/
4271
4272 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4273 {
4274     static long defwndproc_counter = 0;
4275     static long beginpaint_counter = 0;
4276     LRESULT ret;
4277     struct message msg;
4278
4279     trace("%p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
4280
4281     switch (message)
4282     {
4283         case WM_NCDESTROY:
4284             ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
4285         /* fall through */
4286         case WM_DESTROY:
4287             ok(GetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
4288             if (test_DestroyWindow_flag)
4289             {
4290                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
4291                 if (style & WS_CHILD)
4292                     lParam = GetWindowLongA(hwnd, GWL_ID);
4293                 else if (style & WS_POPUP)
4294                     lParam = WND_POPUP_ID;
4295                 else
4296                     lParam = WND_PARENT_ID;
4297             }
4298             break;
4299
4300         /* test_accelerators() depends on this */
4301         case WM_NCHITTEST:
4302             return HTCLIENT;
4303     
4304         /* ignore */
4305         case WM_MOUSEMOVE:
4306         case WM_SETCURSOR:
4307         case WM_DEVICECHANGE:
4308             return 0;
4309
4310         case WM_WINDOWPOSCHANGING:
4311         case WM_WINDOWPOSCHANGED:
4312         {
4313             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
4314
4315             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
4316             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
4317                   winpos->hwnd, winpos->hwndInsertAfter,
4318                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
4319
4320             /* Log only documented flags, win2k uses 0x1000 and 0x2000
4321              * in the high word for internal purposes
4322              */
4323             wParam = winpos->flags & 0xffff;
4324             break;
4325         }
4326     }
4327
4328     msg.message = message;
4329     msg.flags = sent|wparam|lparam;
4330     if (defwndproc_counter) msg.flags |= defwinproc;
4331     if (beginpaint_counter) msg.flags |= beginpaint;
4332     msg.wParam = wParam;
4333     msg.lParam = lParam;
4334     add_message(&msg);
4335
4336     if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
4337     {
4338         HWND parent = GetParent(hwnd);
4339         RECT rc;
4340         MINMAXINFO *minmax = (MINMAXINFO *)lParam;
4341
4342         GetClientRect(parent, &rc);
4343         trace("parent %p client size = (%ld x %ld)\n", parent, rc.right, rc.bottom);
4344
4345         trace("ptReserved = (%ld,%ld)\n"
4346               "ptMaxSize = (%ld,%ld)\n"
4347               "ptMaxPosition = (%ld,%ld)\n"
4348               "ptMinTrackSize = (%ld,%ld)\n"
4349               "ptMaxTrackSize = (%ld,%ld)\n",
4350               minmax->ptReserved.x, minmax->ptReserved.y,
4351               minmax->ptMaxSize.x, minmax->ptMaxSize.y,
4352               minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
4353               minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
4354               minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
4355
4356         ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %ld != %ld\n",
4357            minmax->ptMaxSize.x, rc.right);
4358         ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %ld != %ld\n",
4359            minmax->ptMaxSize.y, rc.bottom);
4360     }
4361
4362     if (message == WM_PAINT)
4363     {
4364         PAINTSTRUCT ps;
4365         beginpaint_counter++;
4366         BeginPaint( hwnd, &ps );
4367         beginpaint_counter--;
4368         EndPaint( hwnd, &ps );
4369         return 0;
4370     }
4371
4372     defwndproc_counter++;
4373     ret = DefWindowProcA(hwnd, message, wParam, lParam);
4374     defwndproc_counter--;
4375
4376     return ret;
4377 }
4378
4379 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4380 {
4381     static long defwndproc_counter = 0;
4382     LRESULT ret;
4383     struct message msg;
4384
4385     trace("popup: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
4386
4387     msg.message = message;
4388     msg.flags = sent|wparam|lparam;
4389     if (defwndproc_counter) msg.flags |= defwinproc;
4390     msg.wParam = wParam;
4391     msg.lParam = lParam;
4392     add_message(&msg);
4393
4394     if (message == WM_CREATE)
4395     {
4396         DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
4397         SetWindowLongA(hwnd, GWL_STYLE, style);
4398     }
4399
4400     defwndproc_counter++;
4401     ret = DefWindowProcA(hwnd, message, wParam, lParam);
4402     defwndproc_counter--;
4403
4404     return ret;
4405 }
4406
4407 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4408 {
4409     static long defwndproc_counter = 0;
4410     static long beginpaint_counter = 0;
4411     LRESULT ret;
4412     struct message msg;
4413
4414     trace("parent: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
4415
4416     if (log_all_parent_messages ||
4417         message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
4418         message == WM_SETFOCUS || message == WM_KILLFOCUS ||
4419         message == WM_ENABLE || message == WM_ENTERIDLE ||
4420         message == WM_IME_SETCONTEXT)
4421     {
4422         msg.message = message;
4423         msg.flags = sent|parent|wparam|lparam;
4424         if (defwndproc_counter) msg.flags |= defwinproc;
4425         if (beginpaint_counter) msg.flags |= beginpaint;
4426         msg.wParam = wParam;
4427         msg.lParam = lParam;
4428         add_message(&msg);
4429     }
4430
4431     if (message == WM_PAINT)
4432     {
4433         PAINTSTRUCT ps;
4434         beginpaint_counter++;
4435         BeginPaint( hwnd, &ps );
4436         beginpaint_counter--;
4437         EndPaint( hwnd, &ps );
4438         return 0;
4439     }
4440
4441     defwndproc_counter++;
4442     ret = DefWindowProcA(hwnd, message, wParam, lParam);
4443     defwndproc_counter--;
4444
4445     return ret;
4446 }
4447
4448 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4449 {
4450     static long defwndproc_counter = 0;
4451     LRESULT ret;
4452     struct message msg;
4453
4454     trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
4455
4456     DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
4457     ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
4458     if (after_end_dialog)
4459         ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
4460     else
4461         ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
4462
4463     switch (message)
4464     {
4465         case WM_WINDOWPOSCHANGING:
4466         case WM_WINDOWPOSCHANGED:
4467         {
4468             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
4469
4470             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
4471             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
4472                   winpos->hwnd, winpos->hwndInsertAfter,
4473                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
4474
4475             /* Log only documented flags, win2k uses 0x1000 and 0x2000
4476              * in the high word for internal purposes
4477              */
4478             wParam = winpos->flags & 0xffff;
4479             break;
4480         }
4481     }
4482
4483     msg.message = message;
4484     msg.flags = sent|wparam|lparam;
4485     if (defwndproc_counter) msg.flags |= defwinproc;
4486     msg.wParam = wParam;
4487     msg.lParam = lParam;
4488     add_message(&msg);
4489
4490     defwndproc_counter++;
4491     ret = DefDlgProcA(hwnd, message, wParam, lParam);
4492     defwndproc_counter--;
4493
4494     return ret;
4495 }
4496
4497 static BOOL RegisterWindowClasses(void)
4498 {
4499     WNDCLASSA cls;
4500
4501     cls.style = 0;
4502     cls.lpfnWndProc = MsgCheckProcA;
4503     cls.cbClsExtra = 0;
4504     cls.cbWndExtra = 0;
4505     cls.hInstance = GetModuleHandleA(0);
4506     cls.hIcon = 0;
4507     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
4508     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
4509     cls.lpszMenuName = NULL;
4510     cls.lpszClassName = "TestWindowClass";
4511     if(!RegisterClassA(&cls)) return FALSE;
4512
4513     cls.lpfnWndProc = PopupMsgCheckProcA;
4514     cls.lpszClassName = "TestPopupClass";
4515     if(!RegisterClassA(&cls)) return FALSE;
4516
4517     cls.lpfnWndProc = ParentMsgCheckProcA;
4518     cls.lpszClassName = "TestParentClass";
4519     if(!RegisterClassA(&cls)) return FALSE;
4520
4521     cls.lpfnWndProc = DefWindowProcA;
4522     cls.lpszClassName = "SimpleWindowClass";
4523     if(!RegisterClassA(&cls)) return FALSE;
4524
4525     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
4526     cls.style = 0;
4527     cls.hInstance = GetModuleHandleA(0);
4528     cls.hbrBackground = 0;
4529     cls.lpfnWndProc = TestDlgProcA;
4530     cls.lpszClassName = "TestDialogClass";
4531     if(!RegisterClassA(&cls)) return FALSE;
4532
4533     return TRUE;
4534 }
4535
4536 static HHOOK hCBT_hook;
4537 static DWORD cbt_hook_thread_id;
4538
4539 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
4540
4541     char buf[256];
4542
4543     trace("CBT: %d, %08x, %08lx\n", nCode, wParam, lParam);
4544
4545     ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
4546
4547     if (nCode == HCBT_SYSCOMMAND)
4548     {
4549         struct message msg;
4550
4551         msg.message = nCode;
4552         msg.flags = hook|wparam|lparam;
4553         msg.wParam = wParam;
4554         msg.lParam = lParam;
4555         add_message(&msg);
4556
4557         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
4558     }
4559
4560     if (nCode == HCBT_DESTROYWND)
4561     {
4562         if (test_DestroyWindow_flag)
4563         {
4564             DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
4565             if (style & WS_CHILD)
4566                 lParam = GetWindowLongA((HWND)wParam, GWL_ID);
4567             else if (style & WS_POPUP)
4568                 lParam = WND_POPUP_ID;
4569             else
4570                 lParam = WND_PARENT_ID;
4571         }
4572     }
4573
4574     /* Log also SetFocus(0) calls */
4575     if (!wParam) wParam = lParam;
4576
4577     if (GetClassNameA((HWND)wParam, buf, sizeof(buf)))
4578     {
4579         if (!lstrcmpiA(buf, "TestWindowClass") ||
4580             !lstrcmpiA(buf, "TestParentClass") ||
4581             !lstrcmpiA(buf, "TestPopupClass") ||
4582             !lstrcmpiA(buf, "SimpleWindowClass") ||
4583             !lstrcmpiA(buf, "TestDialogClass") ||
4584             !lstrcmpiA(buf, "MDI_frame_class") ||
4585             !lstrcmpiA(buf, "MDI_client_class") ||
4586             !lstrcmpiA(buf, "MDI_child_class") ||
4587             !lstrcmpiA(buf, "my_button_class") ||
4588             !lstrcmpiA(buf, "static") ||
4589             !lstrcmpiA(buf, "#32770"))
4590         {
4591             struct message msg;
4592
4593             msg.message = nCode;
4594             msg.flags = hook|wparam|lparam;
4595             msg.wParam = wParam;
4596             msg.lParam = lParam;
4597             add_message(&msg);
4598         }
4599     }
4600     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
4601 }
4602
4603 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
4604                                     DWORD event,
4605                                     HWND hwnd,
4606                                     LONG object_id,
4607                                     LONG child_id,
4608                                     DWORD thread_id,
4609                                     DWORD event_time)
4610 {
4611     char buf[256];
4612
4613     trace("WEH:%p,event %08lx,hwnd %p,obj %08lx,id %08lx,thread %08lx,time %08lx\n",
4614            hevent, event, hwnd, object_id, child_id, thread_id, event_time);
4615
4616     ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
4617
4618     /* ignore mouse cursor events */
4619     if (object_id == OBJID_CURSOR) return;
4620
4621     if (!hwnd || GetClassNameA(hwnd, buf, sizeof(buf)))
4622     {
4623         if (!hwnd ||
4624             !lstrcmpiA(buf, "TestWindowClass") ||
4625             !lstrcmpiA(buf, "TestParentClass") ||
4626             !lstrcmpiA(buf, "TestPopupClass") ||
4627             !lstrcmpiA(buf, "SimpleWindowClass") ||
4628             !lstrcmpiA(buf, "TestDialogClass") ||
4629             !lstrcmpiA(buf, "MDI_frame_class") ||
4630             !lstrcmpiA(buf, "MDI_client_class") ||
4631             !lstrcmpiA(buf, "MDI_child_class") ||
4632             !lstrcmpiA(buf, "my_button_class") ||
4633             !lstrcmpiA(buf, "static") ||
4634             !lstrcmpiA(buf, "#32770"))
4635         {
4636             struct message msg;
4637
4638             msg.message = event;
4639             msg.flags = winevent_hook|wparam|lparam;
4640             msg.wParam = object_id;
4641             msg.lParam = child_id;
4642             add_message(&msg);
4643         }
4644     }
4645 }
4646
4647 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
4648 static const WCHAR wszAnsi[] = {'U',0};
4649
4650 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
4651 {
4652     switch (uMsg)
4653     {
4654     case CB_FINDSTRINGEXACT:
4655         trace("String: %p\n", (LPCWSTR)lParam);
4656         if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
4657             return 1;
4658         if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
4659             return 0;
4660         return -1;
4661     }
4662     return DefWindowProcW(hwnd, uMsg, wParam, lParam);
4663 }
4664
4665 static void test_message_conversion(void)
4666 {
4667     static const WCHAR wszMsgConversionClass[] =
4668         {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
4669     WNDCLASSW cls;
4670     LRESULT lRes;
4671     HWND hwnd;
4672     WNDPROC wndproc;
4673
4674     cls.style = 0;
4675     cls.lpfnWndProc = MsgConversionProcW;
4676     cls.cbClsExtra = 0;
4677     cls.cbWndExtra = 0;
4678     cls.hInstance = GetModuleHandleW(NULL);
4679     cls.hIcon = NULL;
4680     cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
4681     cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
4682     cls.lpszMenuName = NULL;
4683     cls.lpszClassName = wszMsgConversionClass;
4684     /* this call will fail on Win9x, but that doesn't matter as this test is
4685      * meaningless on those platforms */
4686     if(!RegisterClassW(&cls)) return;
4687
4688     hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
4689                            100, 100, 200, 200, 0, 0, 0, NULL);
4690     ok(hwnd != NULL, "Window creation failed\n");
4691
4692     /* {W, A} -> A */
4693
4694     wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
4695     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4696     ok(lRes == 0, "String should have been converted\n");
4697     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4698     ok(lRes == 1, "String shouldn't have been converted\n");
4699
4700     /* {W, A} -> W */
4701
4702     wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
4703     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4704     ok(lRes == 1, "String shouldn't have been converted\n");
4705     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4706     ok(lRes == 1, "String shouldn't have been converted\n");
4707
4708     /* Synchronous messages */
4709
4710     lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4711     ok(lRes == 0, "String should have been converted\n");
4712     lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4713     ok(lRes == 1, "String shouldn't have been converted\n");
4714
4715     /* Asynchronous messages */
4716
4717     SetLastError(0);
4718     lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4719     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4720         "PostMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4721     SetLastError(0);
4722     lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4723     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4724         "PostMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4725     SetLastError(0);
4726     lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4727     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4728         "PosThreadtMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4729     SetLastError(0);
4730     lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4731     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4732         "PosThreadtMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4733     SetLastError(0);
4734     lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4735     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4736         "SendNotifyMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4737     SetLastError(0);
4738     lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
4739     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4740         "SendNotifyMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4741     SetLastError(0);
4742     lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
4743     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4744         "SendMessageCallback on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4745     SetLastError(0);
4746     lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
4747     ok(lRes == 0 && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4748         "SendMessageCallback on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
4749 }
4750
4751 typedef struct _thread_info
4752 {
4753     HWND hWnd;
4754     HANDLE handles[2];
4755     DWORD id;
4756 } thread_info;
4757
4758 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT id, DWORD dwTime)
4759 {
4760 }
4761
4762 #define TIMER_ID  0x19
4763
4764 static DWORD WINAPI timer_thread_proc(LPVOID x)
4765 {
4766     thread_info *info = x;
4767     DWORD r;
4768
4769     r = KillTimer(info->hWnd, 0x19);
4770     ok(r,"KillTimer failed in thread\n");
4771     r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
4772     ok(r,"SetTimer failed in thread\n");
4773     ok(r==TIMER_ID,"SetTimer id different\n");
4774     r = SetEvent(info->handles[0]);
4775     ok(r,"SetEvent failed in thread\n");
4776     return 0;
4777 }
4778
4779 static void test_timers(void)
4780 {
4781     thread_info info;
4782     DWORD id;
4783
4784     info.hWnd = CreateWindow ("TestWindowClass", NULL,
4785        WS_OVERLAPPEDWINDOW ,
4786        CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4787        NULL, NULL, 0);
4788
4789     info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
4790     ok(info.id, "SetTimer failed\n");
4791     ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
4792     info.handles[0] = CreateEvent(NULL,0,0,NULL);
4793     info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
4794
4795     WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
4796
4797     WaitForSingleObject(info.handles[1], INFINITE);
4798
4799     CloseHandle(info.handles[0]);
4800     CloseHandle(info.handles[1]);
4801
4802     ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
4803
4804     ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
4805 }
4806
4807 /* Various win events with arbitrary parameters */
4808 static const struct message WmWinEventsSeq[] = {
4809     { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
4810     { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
4811     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
4812     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
4813     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
4814     { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
4815     { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
4816     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
4817     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
4818     /* our win event hook ignores OBJID_CURSOR events */
4819     /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
4820     { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
4821     { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
4822     { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
4823     { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
4824     { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
4825     { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
4826     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
4827     { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
4828     { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
4829     { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
4830     { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
4831     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
4832     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
4833     { 0 }
4834 };
4835 static const struct message WmWinEventCaretSeq[] = {
4836     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
4837     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
4838     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
4839     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
4840     { 0 }
4841 };
4842 static const struct message WmWinEventCaretSeq_2[] = {
4843     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
4844     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
4845     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
4846     { 0 }
4847 };
4848 static const struct message WmWinEventAlertSeq[] = {
4849     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
4850     { 0 }
4851 };
4852 static const struct message WmWinEventAlertSeq_2[] = {
4853     /* create window in the thread proc */
4854     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
4855     /* our test event */
4856     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
4857     { 0 }
4858 };
4859 static const struct message WmGlobalHookSeq_1[] = {
4860     /* create window in the thread proc */
4861     { HCBT_CREATEWND, hook|lparam, 0, 2 },
4862     /* our test events */
4863     { HCBT_SETFOCUS, hook|lparam, 0, 2 }, /* SetFocus(0) */
4864     { HCBT_ACTIVATE, hook|lparam, 0, 2 },
4865     { HCBT_SETFOCUS, hook|lparam, 0, 2 }, /* SetFocus(hwnd) */
4866     { 0 }
4867 };
4868 static const struct message WmGlobalHookSeq_2[] = {
4869     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
4870     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
4871     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
4872     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
4873     { 0 }
4874 };
4875
4876 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
4877                                          DWORD event,
4878                                          HWND hwnd,
4879                                          LONG object_id,
4880                                          LONG child_id,
4881                                          DWORD thread_id,
4882                                          DWORD event_time)
4883 {
4884     char buf[256];
4885
4886     trace("WEH_2:%p,event %08lx,hwnd %p,obj %08lx,id %08lx,thread %08lx,time %08lx\n",
4887            hevent, event, hwnd, object_id, child_id, thread_id, event_time);
4888
4889     if (GetClassNameA(hwnd, buf, sizeof(buf)))
4890     {
4891         if (!lstrcmpiA(buf, "TestWindowClass") ||
4892             !lstrcmpiA(buf, "static"))
4893         {
4894             struct message msg;
4895
4896             msg.message = event;
4897             msg.flags = winevent_hook|wparam|lparam;
4898             msg.wParam = object_id;
4899             msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
4900             add_message(&msg);
4901         }
4902     }
4903 }
4904
4905 static HHOOK hCBT_global_hook;
4906 static DWORD cbt_global_hook_thread_id;
4907
4908 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
4909
4910     char buf[256];
4911
4912     trace("CBT_2: %d, %08x, %08lx\n", nCode, wParam, lParam);
4913
4914     if (nCode == HCBT_SYSCOMMAND)
4915     {
4916         struct message msg;
4917
4918         msg.message = nCode;
4919         msg.flags = hook|wparam|lparam;
4920         msg.wParam = wParam;
4921         msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
4922         add_message(&msg);
4923
4924         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
4925     }
4926
4927     /* Log also SetFocus(0) calls */
4928     if (!wParam) wParam = lParam;
4929
4930     if (GetClassNameA((HWND)wParam, buf, sizeof(buf)))
4931     {
4932         if (!lstrcmpiA(buf, "TestWindowClass") ||
4933             !lstrcmpiA(buf, "static"))
4934         {
4935             struct message msg;
4936
4937             msg.message = nCode;
4938             msg.flags = hook|wparam|lparam;
4939             msg.wParam = wParam;
4940             msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
4941             add_message(&msg);
4942         }
4943     }
4944     return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
4945 }
4946
4947 static DWORD WINAPI win_event_global_thread_proc(void *param)
4948 {
4949     HWND hwnd;
4950     MSG msg;
4951     HANDLE hevent = *(HANDLE *)param;
4952     HMODULE user32 = GetModuleHandleA("user32.dll");
4953     FARPROC pNotifyWinEvent = GetProcAddress(user32, "NotifyWinEvent");
4954
4955     assert(pNotifyWinEvent);
4956
4957     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
4958     assert(hwnd);
4959     trace("created thread window %p\n", hwnd);
4960
4961     *(HWND *)param = hwnd;
4962
4963     flush_sequence();
4964     /* this event should be received only by our new hook proc,
4965      * an old one does not expect an event from another thread.
4966      */
4967     pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
4968     SetEvent(hevent);
4969
4970     while (GetMessage(&msg, 0, 0, 0))
4971     {
4972         TranslateMessage(&msg);
4973         DispatchMessage(&msg);
4974     }
4975     return 0;
4976 }
4977
4978 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
4979 {
4980     HWND hwnd;
4981     MSG msg;
4982     HANDLE hevent = *(HANDLE *)param;
4983
4984     flush_sequence();
4985     /* these events should be received only by our new hook proc,
4986      * an old one does not expect an event from another thread.
4987      */
4988
4989     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
4990     assert(hwnd);
4991     trace("created thread window %p\n", hwnd);
4992
4993     *(HWND *)param = hwnd;
4994
4995     /* generate focus related CBT events */
4996     SetFocus(0);
4997     SetFocus(hwnd);
4998
4999     SetEvent(hevent);
5000
5001     while (GetMessage(&msg, 0, 0, 0))
5002     {
5003         TranslateMessage(&msg);
5004         DispatchMessage(&msg);
5005     }
5006     return 0;
5007 }
5008
5009 static void test_winevents(void)
5010 {
5011     MSG msg;
5012     HWND hwnd, hwnd2;
5013     UINT i;
5014     HANDLE hthread, hevent;
5015     DWORD tid;
5016     HWINEVENTHOOK hhook;
5017     const struct message *events = WmWinEventsSeq;
5018     HMODULE user32 = GetModuleHandleA("user32.dll");
5019     FARPROC pSetWinEventHook = GetProcAddress(user32, "SetWinEventHook");
5020     FARPROC pUnhookWinEvent = GetProcAddress(user32, "UnhookWinEvent");
5021     FARPROC pNotifyWinEvent = GetProcAddress(user32, "NotifyWinEvent");
5022
5023     hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
5024                            WS_OVERLAPPEDWINDOW,
5025                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5026                            NULL, NULL, 0);
5027     assert(hwnd);
5028
5029     /****** start of global hook test *************/
5030     hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
5031     assert(hCBT_global_hook);
5032
5033     hevent = CreateEventA(NULL, 0, 0, NULL);
5034     assert(hevent);
5035     hwnd2 = (HWND)hevent;
5036
5037     hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
5038     ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError());
5039
5040     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5041
5042     ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
5043
5044     flush_sequence();
5045     /* this one should be received only by old hook proc */
5046     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
5047     /* this one should be received only by old hook proc */
5048     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
5049
5050     ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
5051
5052     ok(UnhookWindowsHookEx(hCBT_global_hook), "UnhookWindowsHookEx error %ld", GetLastError());
5053
5054     PostThreadMessageA(tid, WM_QUIT, 0, 0);
5055     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5056     CloseHandle(hthread);
5057     CloseHandle(hevent);
5058     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
5059     /****** end of global hook test *************/
5060
5061     if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
5062     {
5063         ok(DestroyWindow(hwnd), "failed to destroy window\n");
5064         return;
5065     }
5066
5067     flush_sequence();
5068
5069 #if 0 /* this test doesn't pass under Win9x */
5070     /* win2k ignores events with hwnd == 0 */
5071     SetLastError(0xdeadbeef);
5072     pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
5073     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
5074        GetLastError() == 0xdeadbeef, /* Win9x */
5075        "unexpected error %ld\n", GetLastError());
5076     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
5077 #endif
5078
5079     for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++)
5080         pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
5081
5082     ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
5083
5084     /****** start of event filtering test *************/
5085     hhook = (HWINEVENTHOOK)pSetWinEventHook(
5086         EVENT_OBJECT_SHOW, /* 0x8002 */
5087         EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
5088         GetModuleHandleA(0), win_event_global_hook_proc,
5089         GetCurrentProcessId(), 0,
5090         WINEVENT_INCONTEXT);
5091     ok(hhook != 0, "SetWinEventHook error %ld\n", GetLastError());
5092
5093     hevent = CreateEventA(NULL, 0, 0, NULL);
5094     assert(hevent);
5095     hwnd2 = (HWND)hevent;
5096
5097     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
5098     ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError());
5099
5100     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5101
5102     ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
5103
5104     flush_sequence();
5105     /* this one should be received only by old hook proc */
5106     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
5107     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
5108     /* this one should be received only by old hook proc */
5109     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
5110
5111     ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
5112
5113     ok(pUnhookWinEvent(hhook), "UnhookWinEvent error %ld\n", GetLastError());
5114
5115     PostThreadMessageA(tid, WM_QUIT, 0, 0);
5116     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5117     CloseHandle(hthread);
5118     CloseHandle(hevent);
5119     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
5120     /****** end of event filtering test *************/
5121
5122     /****** start of out of context event test *************/
5123     hhook = (HWINEVENTHOOK)pSetWinEventHook(
5124         EVENT_MIN, EVENT_MAX,
5125         0, win_event_global_hook_proc,
5126         GetCurrentProcessId(), 0,
5127         WINEVENT_OUTOFCONTEXT);
5128     ok(hhook != 0, "SetWinEventHook error %ld\n", GetLastError());
5129
5130     hevent = CreateEventA(NULL, 0, 0, NULL);
5131     assert(hevent);
5132     hwnd2 = (HWND)hevent;
5133
5134     flush_sequence();
5135
5136     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
5137     ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError());
5138
5139     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5140
5141     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
5142     /* process pending winevent messages */
5143     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
5144     ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
5145
5146     flush_sequence();
5147     /* this one should be received only by old hook proc */
5148     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
5149     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
5150     /* this one should be received only by old hook proc */
5151     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
5152
5153     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
5154     /* process pending winevent messages */
5155     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
5156     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
5157
5158     ok(pUnhookWinEvent(hhook), "UnhookWinEvent error %ld\n", GetLastError());
5159
5160     PostThreadMessageA(tid, WM_QUIT, 0, 0);
5161     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5162     CloseHandle(hthread);
5163     CloseHandle(hevent);
5164     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
5165     /****** end of out of context event test *************/
5166
5167     ok(DestroyWindow(hwnd), "failed to destroy window\n");
5168 }
5169
5170 static void test_set_hook(void)
5171 {
5172     HHOOK hhook;
5173     HWINEVENTHOOK hwinevent_hook;
5174     HMODULE user32 = GetModuleHandleA("user32.dll");
5175     FARPROC pSetWinEventHook = GetProcAddress(user32, "SetWinEventHook");
5176     FARPROC pUnhookWinEvent = GetProcAddress(user32, "UnhookWinEvent");
5177
5178     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
5179     ok(hhook != 0, "local hook does not require hModule set to 0\n");
5180     UnhookWindowsHookEx(hhook);
5181
5182 #if 0 /* this test doesn't pass under Win9x: BUG! */
5183     SetLastError(0xdeadbeef);
5184     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
5185     ok(!hhook, "global hook requires hModule != 0\n");
5186     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %ld\n", GetLastError());
5187 #endif
5188
5189     SetLastError(0xdeadbeef);
5190     hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
5191     ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
5192     ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
5193        GetLastError() == 0xdeadbeef, /* Win9x */
5194        "unexpected error %ld\n", GetLastError());
5195
5196     SetLastError(0xdeadbeef);
5197     ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
5198     ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
5199        GetLastError() == 0xdeadbeef, /* Win9x */
5200        "unexpected error %ld\n", GetLastError());
5201
5202     if (!pSetWinEventHook || !pUnhookWinEvent) return;
5203
5204     /* even process local incontext hooks require hmodule */
5205     SetLastError(0xdeadbeef);
5206     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
5207         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
5208     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
5209     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
5210        GetLastError() == 0xdeadbeef, /* Win9x */
5211        "unexpected error %ld\n", GetLastError());
5212
5213     /* even thread local incontext hooks require hmodule */
5214     SetLastError(0xdeadbeef);
5215     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
5216         0, win_event_proc, GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
5217     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
5218     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
5219        GetLastError() == 0xdeadbeef, /* Win9x */
5220        "unexpected error %ld\n", GetLastError());
5221
5222 #if 0 /* these 3 tests don't pass under Win9x */
5223     SetLastError(0xdeadbeef);
5224     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(1, 0,
5225         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
5226     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
5227     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %ld\n", GetLastError());
5228
5229     SetLastError(0xdeadbeef);
5230     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(-1, 1,
5231         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
5232     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
5233     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %ld\n", GetLastError());
5234
5235     SetLastError(0xdeadbeef);
5236     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
5237         0, win_event_proc, 0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
5238     ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
5239     ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %ld\n", GetLastError());
5240 #endif
5241
5242     SetLastError(0xdeadbeef);
5243     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(0, 0,
5244         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
5245     ok(hwinevent_hook != 0, "SetWinEventHook error %ld\n", GetLastError());
5246     ok(GetLastError() == 0xdeadbeef, "unexpected error %ld\n", GetLastError());
5247     ok(pUnhookWinEvent(hwinevent_hook), "UnhookWinEvent error %ld\n", GetLastError());
5248
5249 todo_wine {
5250     /* This call succeeds under win2k SP4, but fails under Wine.
5251        Does win2k test/use passed process id? */
5252     SetLastError(0xdeadbeef);
5253     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
5254         0, win_event_proc, 0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
5255     ok(hwinevent_hook != 0, "SetWinEventHook error %ld\n", GetLastError());
5256     ok(GetLastError() == 0xdeadbeef, "unexpected error %ld\n", GetLastError());
5257     ok(pUnhookWinEvent(hwinevent_hook), "UnhookWinEvent error %ld\n", GetLastError());
5258 }
5259
5260     SetLastError(0xdeadbeef);
5261     ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
5262     ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
5263         GetLastError() == 0xdeadbeef, /* Win9x */
5264         "unexpected error %ld\n", GetLastError());
5265 }
5266
5267 static const struct message ScrollWindowPaint1[] = {
5268     { WM_PAINT, sent },
5269     { WM_ERASEBKGND, sent|beginpaint },
5270     { 0 }
5271 };
5272
5273 static const struct message ScrollWindowPaint2[] = {
5274     { WM_PAINT, sent },
5275     { 0 }
5276 };
5277
5278 static void test_scrollwindowex(void)
5279 {
5280     HWND hwnd, hchild;
5281     RECT rect={0,0,130,130};
5282     MSG msg;
5283
5284     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
5285             WS_VISIBLE|WS_OVERLAPPEDWINDOW,
5286             100, 100, 200, 200, 0, 0, 0, NULL);
5287     ok (hwnd != 0, "Failed to create overlapped window\n");
5288     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", 
5289             WS_VISIBLE|WS_CAPTION|WS_CHILD,
5290             10, 10, 150, 150, hwnd, 0, 0, NULL);
5291     ok (hchild != 0, "Failed to create child\n");
5292     UpdateWindow(hwnd);
5293     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5294     flush_sequence();
5295
5296     /* scroll without the child window */
5297     trace("start scroll\n");
5298     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
5299             SW_ERASE|SW_INVALIDATE);
5300     ok_sequence(WmEmptySeq, "ScrollWindowEx\n", 0);
5301     trace("end scroll\n");
5302     flush_sequence();
5303     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5304     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx\n", 0);
5305
5306     /* Now without the SW_ERASE flag */
5307     trace("start scroll\n");
5308     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
5309     ok_sequence(WmEmptySeq, "ScrollWindowEx\n", 0);
5310     trace("end scroll\n");
5311     flush_sequence();
5312     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5313     ok_sequence(ScrollWindowPaint2, "ScrollWindowEx\n", 0);
5314
5315     /* now scroll the child window as well */
5316     trace("start scroll\n");
5317     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
5318             SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
5319     todo_wine { /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
5320                 /* windows sometimes a WM_MOVE */
5321         ok_sequence(WmEmptySeq, "ScrollWindowEx\n", 0);
5322     }
5323     trace("end scroll\n");
5324     flush_sequence();
5325     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5326     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx\n", 0);
5327
5328     ok(DestroyWindow(hchild), "failed to destroy window\n");
5329     ok(DestroyWindow(hwnd), "failed to destroy window\n");
5330     flush_sequence();
5331 }
5332
5333 static const struct message destroy_window_with_children[] = {
5334     { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
5335     { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
5336     { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
5337     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
5338     { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
5339     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
5340     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
5341     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
5342     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
5343     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
5344     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
5345     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
5346     { 0 }
5347 };
5348
5349 static void test_DestroyWindow(void)
5350 {
5351     HWND parent, child1, child2, child3, child4, test;
5352     UINT child_id = WND_CHILD_ID + 1;
5353
5354     parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
5355                              100, 100, 200, 200, 0, 0, 0, NULL);
5356     assert(parent != 0);
5357     child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
5358                              0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
5359     assert(child1 != 0);
5360     child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
5361                              0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
5362     assert(child2 != 0);
5363     child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
5364                              0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
5365     assert(child3 != 0);
5366     child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
5367                              0, 0, 50, 50, parent, 0, 0, NULL);
5368     assert(child4 != 0);
5369
5370     /* test owner/parent of child2 */
5371     test = GetParent(child2);
5372     ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
5373     test = GetAncestor(child2, GA_PARENT);
5374     ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
5375     test = GetWindow(child2, GW_OWNER);
5376     ok(!test, "wrong owner %p\n", test);
5377
5378     test = SetParent(child2, parent);
5379     ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
5380
5381     /* test owner/parent of the parent */
5382     test = GetParent(parent);
5383     ok(!test, "wrong parent %p\n", test);
5384     test = GetAncestor(parent, GA_PARENT);
5385     ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
5386     test = GetWindow(parent, GW_OWNER);
5387     ok(!test, "wrong owner %p\n", test);
5388
5389     /* test owner/parent of child1 */
5390     test = GetParent(child1);
5391     ok(test == parent, "wrong parent %p\n", test);
5392     test = GetAncestor(child1, GA_PARENT);
5393     ok(test == parent, "wrong parent %p\n", test);
5394     test = GetWindow(child1, GW_OWNER);
5395     ok(!test, "wrong owner %p\n", test);
5396
5397     /* test owner/parent of child2 */
5398     test = GetParent(child2);
5399     ok(test == parent, "wrong parent %p\n", test);
5400     test = GetAncestor(child2, GA_PARENT);
5401     ok(test == parent, "wrong parent %p\n", test);
5402     test = GetWindow(child2, GW_OWNER);
5403     ok(!test, "wrong owner %p\n", test);
5404
5405     /* test owner/parent of child3 */
5406     test = GetParent(child3);
5407     ok(test == child1, "wrong parent %p\n", test);
5408     test = GetAncestor(child3, GA_PARENT);
5409     ok(test == child1, "wrong parent %p\n", test);
5410     test = GetWindow(child3, GW_OWNER);
5411     ok(!test, "wrong owner %p\n", test);
5412
5413     /* test owner/parent of child4 */
5414     test = GetParent(child4);
5415     ok(test == parent, "wrong parent %p\n", test);
5416     test = GetAncestor(child4, GA_PARENT);
5417     ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
5418     test = GetWindow(child4, GW_OWNER);
5419     ok(test == parent, "wrong owner %p\n", test);
5420
5421     flush_sequence();
5422
5423     trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
5424            parent, child1, child2, child3, child4);
5425
5426     test_DestroyWindow_flag = TRUE;
5427     ok(DestroyWindow(parent), "DestroyWindow() error %ld\n", GetLastError());
5428     test_DestroyWindow_flag = FALSE;
5429     ok_sequence(destroy_window_with_children, "destroy window with children\n", 0);
5430
5431     ok(!IsWindow(parent), "parent still exists");
5432     ok(!IsWindow(child1), "child1 still exists");
5433     ok(!IsWindow(child2), "child2 still exists");
5434     ok(!IsWindow(child3), "child3 still exists");
5435     ok(!IsWindow(child4), "child4 still exists");
5436 }
5437
5438 START_TEST(msg)
5439 {
5440     HMODULE user32 = GetModuleHandleA("user32.dll");
5441     FARPROC pSetWinEventHook = GetProcAddress(user32, "SetWinEventHook");
5442     FARPROC pUnhookWinEvent = GetProcAddress(user32, "UnhookWinEvent");
5443     FARPROC pIsWinEventHookInstalled = 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
5444
5445     if (!RegisterWindowClasses()) assert(0);
5446
5447     if (pSetWinEventHook)
5448     {
5449         hEvent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
5450                                                       GetModuleHandleA(0),
5451                                                       win_event_proc,
5452                                                       0,
5453                                                       GetCurrentThreadId(),
5454                                                       WINEVENT_INCONTEXT);
5455         assert(hEvent_hook);
5456
5457         if (pIsWinEventHookInstalled)
5458         {
5459             UINT event;
5460             for (event = EVENT_MIN; event <= EVENT_MAX; event++)
5461                 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
5462         }
5463     }
5464
5465     cbt_hook_thread_id = GetCurrentThreadId();
5466     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
5467     assert(hCBT_hook);
5468
5469     test_winevents();
5470
5471     /* Fix message sequences before removing 3 lines below */
5472     ok(pUnhookWinEvent(hEvent_hook), "UnhookWinEvent error %ld\n", GetLastError());
5473     pUnhookWinEvent = 0;
5474     hEvent_hook = 0;
5475
5476     test_scrollwindowex();
5477     test_messages();
5478     test_mdi_messages();
5479     test_button_messages();
5480     test_paint_messages();
5481     test_interthread_messages();
5482     test_message_conversion();
5483     test_accelerators();
5484     test_timers();
5485     test_set_hook();
5486     test_DestroyWindow();
5487
5488     UnhookWindowsHookEx(hCBT_hook);
5489     if (pUnhookWinEvent)
5490     {
5491         ok(pUnhookWinEvent(hEvent_hook), "UnhookWinEvent error %ld\n", GetLastError());
5492         SetLastError(0xdeadbeef);
5493         ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
5494         ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
5495            GetLastError() == 0xdeadbeef, /* Win9x */
5496            "unexpected error %ld\n", GetLastError());
5497     }
5498 }