mcicda: Exclude unused headers.
[wine] / dlls / user32 / 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include <assert.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26
27 #define _WIN32_WINNT 0x0501 /* For WM_CHANGEUISTATE,QS_RAWINPUT */
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33 #include "winnls.h"
34
35 #include "wine/test.h"
36
37 #define MDI_FIRST_CHILD_ID 2004
38
39 /* undocumented SWP flags - from SDK 3.1 */
40 #define SWP_NOCLIENTSIZE        0x0800
41 #define SWP_NOCLIENTMOVE        0x1000
42
43 #define SW_NORMALNA             0xCC    /* undoc. flag in MinMaximize */
44
45 #ifndef WM_SYSTIMER
46 #define WM_SYSTIMER         0x0118
47 #endif
48
49 #define WND_PARENT_ID           1
50 #define WND_POPUP_ID            2
51 #define WND_CHILD_ID            3
52
53 static BOOL test_DestroyWindow_flag;
54 static HWINEVENTHOOK hEvent_hook;
55
56 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
57
58 static void dump_winpos_flags(UINT flags);
59
60 /*
61 FIXME: add tests for these
62 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
63  WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
64  WS_THICKFRAME: thick border
65  WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
66  WS_BORDER (default for overlapped windows): single black border
67  none (default for child (and popup?) windows): no border
68 */
69
70 typedef enum {
71     sent=0x1,
72     posted=0x2,
73     parent=0x4,
74     wparam=0x8,
75     lparam=0x10,
76     defwinproc=0x20,
77     beginpaint=0x40,
78     optional=0x80,
79     hook=0x100,
80     winevent_hook=0x200
81 } msg_flags_t;
82
83 struct message {
84     UINT message;          /* the WM_* code */
85     msg_flags_t flags;     /* message props */
86     WPARAM wParam;         /* expected value of wParam */
87     LPARAM lParam;         /* expected value of lParam */
88 };
89
90 /* Empty message sequence */
91 static const struct message WmEmptySeq[] =
92 {
93     { 0 }
94 };
95 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
96 static const struct message WmCreateOverlappedSeq[] = {
97     { HCBT_CREATEWND, hook },
98     { WM_GETMINMAXINFO, sent },
99     { WM_NCCREATE, sent },
100     { WM_NCCALCSIZE, sent|wparam, 0 },
101     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
102     { WM_CREATE, sent },
103     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
104     { 0 }
105 };
106 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
107  * for a not visible overlapped window.
108  */
109 static const struct message WmSWP_ShowOverlappedSeq[] = {
110     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
111     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
112     { WM_NCPAINT, sent|wparam|optional, 1 },
113     { WM_GETTEXT, sent|defwinproc|optional },
114     { WM_ERASEBKGND, sent|optional },
115     { HCBT_ACTIVATE, hook },
116     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
117     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
118     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
119     { WM_ACTIVATEAPP, sent|wparam, 1 },
120     { WM_NCACTIVATE, sent|wparam, 1 },
121     { WM_GETTEXT, sent|defwinproc|optional },
122     { WM_ACTIVATE, sent|wparam, 1 },
123     { HCBT_SETFOCUS, hook },
124     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
125     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
126     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
127     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
128     { WM_NCPAINT, sent|wparam|optional, 1 },
129     { WM_GETTEXT, sent|defwinproc|optional },
130     { WM_ERASEBKGND, sent|optional },
131     /* Win9x adds SWP_NOZORDER below */
132     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
133     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
134     { WM_NCPAINT, sent|wparam|optional, 1 },
135     { WM_ERASEBKGND, sent|optional },
136     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
137     { 0 }
138 };
139 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
140  * for a visible overlapped window.
141  */
142 static const struct message WmSWP_HideOverlappedSeq[] = {
143     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
144     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
145     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
146     { 0 }
147 };
148
149 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
150  * for a visible overlapped window.
151  */
152 static const struct message WmSWP_ResizeSeq[] = {
153     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
154     { WM_GETMINMAXINFO, sent|defwinproc },
155     { WM_NCCALCSIZE, sent|wparam, TRUE },
156     { WM_NCPAINT, sent|optional },
157     { WM_GETTEXT, sent|defwinproc|optional },
158     { WM_ERASEBKGND, sent|optional },
159     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
160     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
161     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
162     { WM_NCPAINT, sent|optional },
163     { WM_GETTEXT, sent|defwinproc|optional },
164     { WM_ERASEBKGND, sent|optional },
165     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
166     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
167     { 0 }
168 };
169
170 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
171  * for a visible popup window.
172  */
173 static const struct message WmSWP_ResizePopupSeq[] = {
174     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
175     { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* Win9x */
176     { WM_NCCALCSIZE, sent|wparam, TRUE },
177     { WM_NCPAINT, sent|optional },
178     { WM_GETTEXT, sent|defwinproc|optional },
179     { WM_ERASEBKGND, sent|optional },
180     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
181     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
182     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
183     { WM_NCPAINT, sent|optional },
184     { WM_GETTEXT, sent|defwinproc|optional },
185     { WM_ERASEBKGND, sent|optional },
186     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
187     { 0 }
188 };
189
190 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE)
191  * for a visible overlapped window.
192  */
193 static const struct message WmSWP_MoveSeq[] = {
194     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE },
195     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
196     { WM_MOVE, sent|defwinproc|wparam, 0 },
197     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
198     { 0 }
199 };
200 /* Resize with SetWindowPos(SWP_NOZORDER)
201  * for a visible overlapped window
202  * SWP_NOZORDER is stripped by the logging code
203  */
204 static const struct message WmSWP_ResizeNoZOrder[] = {
205     { WM_WINDOWPOSCHANGING, sent|wparam, 0/*SWP_NOZORDER*/ },
206     { WM_GETMINMAXINFO, sent|defwinproc },
207     { WM_NCCALCSIZE, sent|wparam, 1 },
208     { WM_NCPAINT, sent },
209     { WM_GETTEXT, sent|defwinproc|optional },
210     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
211     { WM_WINDOWPOSCHANGED, sent|wparam, /*SWP_NOZORDER|*/SWP_NOMOVE|SWP_NOCLIENTMOVE },
212     { WM_SIZE, sent|defwinproc|wparam, 0 },
213     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
214     { WM_NCPAINT, sent|optional }, /* Win9x doesn't send it */
215     { WM_GETTEXT, sent|defwinproc|optional }, /* Win9x doesn't send it */
216     { WM_ERASEBKGND, sent|optional }, /* Win9x doesn't send it */
217     { 0 }
218 };
219
220 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
221                 SWP_NOZORDER|SWP_FRAMECHANGED)
222  * for a visible overlapped window with WS_CLIPCHILDREN style set.
223  */
224 static const struct message WmSWP_FrameChanged_clip[] = {
225     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
226     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
227     { WM_NCPAINT, sent|parent }, /* wparam != 1 */
228     { WM_GETTEXT, sent|parent|defwinproc|optional },
229     { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
230     { WM_NCPAINT, sent }, /* wparam != 1 */
231     { WM_ERASEBKGND, sent },
232     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
233     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
234     { WM_PAINT, sent },
235     { 0 }
236 };
237 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|
238                 SWP_NOZORDER|SWP_FRAMECHANGED)
239  * for a visible overlapped window.
240  */
241 static const struct message WmSWP_FrameChangedDeferErase[] = {
242     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
243     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
244     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
245     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
246     { WM_PAINT, sent|parent },
247     { WM_NCPAINT, sent|beginpaint|parent }, /* wparam != 1 */
248     { WM_GETTEXT, sent|beginpaint|parent|defwinproc|optional },
249     { WM_PAINT, sent },
250     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
251     { WM_ERASEBKGND, sent|beginpaint },
252     { 0 }
253 };
254
255 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
256                 SWP_NOZORDER|SWP_FRAMECHANGED)
257  * for a visible overlapped window without WS_CLIPCHILDREN style set.
258  */
259 static const struct message WmSWP_FrameChanged_noclip[] = {
260     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
261     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
262     { WM_NCPAINT, sent|parent }, /* wparam != 1 */
263     { WM_GETTEXT, sent|parent|defwinproc|optional },
264     { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
265     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
266     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
267     { WM_PAINT, sent },
268     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
269     { WM_ERASEBKGND, sent|beginpaint },
270     { 0 }
271 };
272
273 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
274 static const struct message WmShowOverlappedSeq[] = {
275     { WM_SHOWWINDOW, sent|wparam, 1 },
276     { WM_NCPAINT, sent|wparam|optional, 1 },
277     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
278     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
279     { WM_NCPAINT, sent|wparam|optional, 1 },
280     { WM_GETTEXT, sent|defwinproc|optional },
281     { WM_ERASEBKGND, sent|optional },
282     { HCBT_ACTIVATE, hook },
283     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
284     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
285     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
286     { WM_NCPAINT, sent|wparam|optional, 1 },
287     { WM_ACTIVATEAPP, sent|wparam, 1 },
288     { WM_NCACTIVATE, sent|wparam, 1 },
289     { WM_GETTEXT, sent|defwinproc|optional },
290     { WM_ACTIVATE, sent|wparam, 1 },
291     { HCBT_SETFOCUS, hook },
292     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
293     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
294     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
295     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
296     { WM_NCPAINT, sent|wparam|optional, 1 },
297     { WM_GETTEXT, sent|defwinproc|optional },
298     { WM_ERASEBKGND, sent|optional },
299     /* Win9x adds SWP_NOZORDER below */
300     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
301     { WM_NCCALCSIZE, sent|optional },
302     { WM_NCPAINT, sent|optional },
303     { WM_ERASEBKGND, sent|optional },
304 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
305        * messages. Does that mean that CreateWindow doesn't set initial
306        * window dimensions for overlapped windows?
307        */
308     { WM_SIZE, sent },
309     { WM_MOVE, sent },
310 #endif
311     { 0 }
312 };
313 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible overlapped window */
314 static const struct message WmShowMaxOverlappedSeq[] = {
315     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
316     { WM_GETMINMAXINFO, sent },
317     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
318     { WM_GETMINMAXINFO, sent|defwinproc },
319     { WM_NCCALCSIZE, sent|wparam, TRUE },
320     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
321     { HCBT_ACTIVATE, hook },
322     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
323     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
324     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
325     { WM_ACTIVATEAPP, sent|wparam, 1 },
326     { WM_NCACTIVATE, sent|wparam, 1 },
327     { WM_GETTEXT, sent|defwinproc|optional },
328     { WM_ACTIVATE, sent|wparam, 1 },
329     { HCBT_SETFOCUS, hook },
330     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
331     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
332     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
333     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
334     { WM_NCPAINT, sent|wparam|optional, 1 },
335     { WM_GETTEXT, sent|defwinproc|optional },
336     { WM_ERASEBKGND, sent|optional },
337     /* Win9x adds SWP_NOZORDER below */
338     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
339     { WM_MOVE, sent|defwinproc },
340     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
341     { WM_NCCALCSIZE, sent|optional },
342     { WM_NCPAINT, sent|optional },
343     { WM_ERASEBKGND, sent|optional },
344     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
345     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
346     { 0 }
347 };
348 /* ShowWindow(SW_SHOWMINIMIZED) for a not visible overlapped window */
349 static const struct message WmShowMinOverlappedSeq[] = {
350     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
351     { HCBT_SETFOCUS, hook },
352     { WM_KILLFOCUS, sent },
353     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
354     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
355     { WM_GETTEXT, sent|optional },
356     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCOPYBITS|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
357     { WM_GETMINMAXINFO, sent|defwinproc },
358     { WM_NCCALCSIZE, sent|wparam, TRUE },
359     { WM_NCPAINT, sent },
360     { WM_GETTEXT, sent|defwinproc|optional },
361     { WM_WINDOWPOSCHANGED, sent },
362     { WM_MOVE, sent|defwinproc },
363     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
364     { WM_NCCALCSIZE, sent|optional },
365     { WM_NCACTIVATE, sent|wparam, 0 },
366     { WM_GETTEXT, sent|defwinproc|optional },
367     { WM_ACTIVATE, sent },
368     { WM_ACTIVATEAPP, sent|wparam, 0 },
369     { 0 }
370 };
371 /* ShowWindow(SW_HIDE) for a visible overlapped window */
372 static const struct message WmHideOverlappedSeq[] = {
373     { WM_SHOWWINDOW, sent|wparam, 0 },
374     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
375     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
376     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
377     { WM_SIZE, sent|optional }, /* XP doesn't send it */
378     { WM_MOVE, sent|optional }, /* XP doesn't send it */
379     { WM_NCACTIVATE, sent|wparam, 0 },
380     { WM_ACTIVATE, sent|wparam, 0 },
381     { WM_ACTIVATEAPP, sent|wparam, 0 },
382     { WM_KILLFOCUS, sent|wparam, 0 },
383     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
384     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
385     { 0 }
386 };
387 /* DestroyWindow for a visible overlapped window */
388 static const struct message WmDestroyOverlappedSeq[] = {
389     { HCBT_DESTROYWND, hook },
390     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
391     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
392     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
393     { WM_NCACTIVATE, sent|wparam, 0 },
394     { WM_ACTIVATE, sent|wparam, 0 },
395     { WM_ACTIVATEAPP, sent|wparam, 0 },
396     { WM_KILLFOCUS, sent|wparam, 0 },
397     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
398     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
399     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
400     { WM_DESTROY, sent },
401     { WM_NCDESTROY, sent },
402     { 0 }
403 };
404 /* CreateWindow(WS_MAXIMIZE|WS_VISIBLE) for popup window */
405 static const struct message WmCreateMaxPopupSeq[] = {
406     { HCBT_CREATEWND, hook },
407     { WM_NCCREATE, sent },
408     { WM_NCCALCSIZE, sent|wparam, 0 },
409     { WM_CREATE, sent },
410     { WM_SIZE, sent|wparam, SIZE_RESTORED },
411     { WM_MOVE, sent },
412     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
413     { WM_GETMINMAXINFO, sent },
414     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|0x8000 },
415     { WM_NCCALCSIZE, sent|wparam, TRUE },
416     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|0x8000 },
417     { WM_MOVE, sent|defwinproc },
418     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
419     { WM_SHOWWINDOW, sent|wparam, 1 },
420     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
421     { HCBT_ACTIVATE, hook },
422     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
423     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
424     { WM_ACTIVATEAPP, sent|wparam, 1 },
425     { WM_NCACTIVATE, sent|wparam, 1 },
426     { WM_ACTIVATE, sent|wparam, 1 },
427     { HCBT_SETFOCUS, hook },
428     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
429     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
430     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
431     { WM_SYNCPAINT, sent|wparam|optional, 4 },
432     { WM_NCPAINT, sent|wparam|optional, 1 },
433     { WM_ERASEBKGND, sent|optional },
434     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
435     { 0 }
436 };
437 /* CreateWindow(WS_MAXIMIZE) for popup window, not initially visible */
438 static const struct message WmCreateInvisibleMaxPopupSeq[] = {
439     { HCBT_CREATEWND, hook },
440     { WM_NCCREATE, sent },
441     { WM_NCCALCSIZE, sent|wparam, 0 },
442     { WM_CREATE, sent },
443     { WM_SIZE, sent|wparam, SIZE_RESTORED },
444     { WM_MOVE, sent },
445     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
446     { WM_GETMINMAXINFO, sent },
447     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|0x8000 },
448     { WM_NCCALCSIZE, sent|wparam, TRUE },
449     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|0x8000 },
450     { WM_MOVE, sent|defwinproc },
451     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
452     { 0 }
453 };
454 /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */
455 static const struct message WmShowMaxPopupResizedSeq[] = {
456     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
457     { WM_GETMINMAXINFO, sent },
458     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
459     { WM_NCCALCSIZE, sent|wparam, TRUE },
460     { HCBT_ACTIVATE, hook },
461     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
462     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
463     { WM_ACTIVATEAPP, sent|wparam, 1 },
464     { WM_NCACTIVATE, sent|wparam, 1 },
465     { WM_ACTIVATE, sent|wparam, 1 },
466     { HCBT_SETFOCUS, hook },
467     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
468     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
469     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
470     { WM_NCPAINT, sent|wparam|optional, 1 },
471     { WM_ERASEBKGND, sent|optional },
472     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE },
473     /* WinNT4.0 sends WM_MOVE */
474     { WM_MOVE, sent|defwinproc|optional },
475     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
476     { 0 }
477 };
478 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible popup window */
479 static const struct message WmShowMaxPopupSeq[] = {
480     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
481     { WM_GETMINMAXINFO, sent },
482     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
483     { WM_NCCALCSIZE, sent|wparam, TRUE },
484     { HCBT_ACTIVATE, hook },
485     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
486     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
487     { WM_ACTIVATEAPP, sent|wparam, 1 },
488     { WM_NCACTIVATE, sent|wparam, 1 },
489     { WM_ACTIVATE, sent|wparam, 1 },
490     { HCBT_SETFOCUS, hook },
491     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
492     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
493     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
494     { WM_SYNCPAINT, sent|wparam|optional, 4 },
495     { WM_NCPAINT, sent|wparam|optional, 1 },
496     { WM_ERASEBKGND, sent|optional },
497     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE },
498     { 0 }
499 };
500 /* CreateWindow(WS_VISIBLE) for popup window */
501 static const struct message WmCreatePopupSeq[] = {
502     { HCBT_CREATEWND, hook },
503     { WM_NCCREATE, sent },
504     { WM_NCCALCSIZE, sent|wparam, 0 },
505     { WM_CREATE, sent },
506     { WM_SIZE, sent|wparam, SIZE_RESTORED },
507     { WM_MOVE, sent },
508     { WM_SHOWWINDOW, sent|wparam, 1 },
509     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
510     { HCBT_ACTIVATE, hook },
511     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
512     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
513     { WM_NCPAINT, sent|wparam|optional, 1 },
514     { WM_ERASEBKGND, sent|optional },
515     { WM_ACTIVATEAPP, sent|wparam, 1 },
516     { WM_NCACTIVATE, sent|wparam, 1 },
517     { WM_ACTIVATE, sent|wparam, 1 },
518     { HCBT_SETFOCUS, hook },
519     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
520     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
521     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
522     { WM_SYNCPAINT, sent|wparam|optional, 4 },
523     { WM_NCPAINT, sent|wparam|optional, 1 },
524     { WM_ERASEBKGND, sent|optional },
525     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
526     { 0 }
527 };
528 /* ShowWindow(SW_SHOWMAXIMIZED) for a visible popup window */
529 static const struct message WmShowVisMaxPopupSeq[] = {
530     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
531     { WM_GETMINMAXINFO, sent },
532     { WM_GETTEXT, sent|optional },
533     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
534     { WM_NCCALCSIZE, sent|wparam, TRUE },
535     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
536     { WM_NCPAINT, sent|wparam|optional, 1 },
537     { WM_ERASEBKGND, sent|optional },
538     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|0x8000 },
539     { WM_MOVE, sent|defwinproc },
540     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
541     { 0 }
542 };
543 /* CreateWindow (for a child popup window, not initially visible) */
544 static const struct message WmCreateChildPopupSeq[] = {
545     { HCBT_CREATEWND, hook },
546     { WM_NCCREATE, sent }, 
547     { WM_NCCALCSIZE, sent|wparam, 0 },
548     { WM_CREATE, sent },
549     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
550     { WM_SIZE, sent|wparam, SIZE_RESTORED },
551     { WM_MOVE, sent },
552     { 0 }
553 };
554 /* CreateWindow (for a popup window, not initially visible,
555  * which sets WS_VISIBLE in WM_CREATE handler)
556  */
557 static const struct message WmCreateInvisiblePopupSeq[] = {
558     { HCBT_CREATEWND, hook },
559     { WM_NCCREATE, sent }, 
560     { WM_NCCALCSIZE, sent|wparam, 0 },
561     { WM_CREATE, sent },
562     { WM_STYLECHANGING, sent },
563     { WM_STYLECHANGED, sent },
564     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
565     { WM_SIZE, sent|wparam, SIZE_RESTORED },
566     { WM_MOVE, sent },
567     { 0 }
568 };
569 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
570  * for a popup window with WS_VISIBLE style set
571  */
572 static const struct message WmShowVisiblePopupSeq_2[] = {
573     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
574     { 0 }
575 };
576 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
577  * for a popup window with WS_VISIBLE style set
578  */
579 static const struct message WmShowVisiblePopupSeq_3[] = {
580     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
581     { HCBT_ACTIVATE, hook },
582     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
583     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
584     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
585     { WM_NCACTIVATE, sent|wparam, 1 },
586     { WM_ACTIVATE, sent|wparam, 1 },
587     { HCBT_SETFOCUS, hook },
588     { WM_KILLFOCUS, sent|parent },
589     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
590     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
591     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
592     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
593     { WM_SETFOCUS, sent|defwinproc },
594     { 0 }
595 };
596 /* CreateWindow (for child window, not initially visible) */
597 static const struct message WmCreateChildSeq[] = {
598     { HCBT_CREATEWND, hook },
599     { WM_NCCREATE, sent }, 
600     /* child is inserted into parent's child list after WM_NCCREATE returns */
601     { WM_NCCALCSIZE, sent|wparam, 0 },
602     { WM_CREATE, sent },
603     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
604     { WM_SIZE, sent|wparam, SIZE_RESTORED },
605     { WM_MOVE, sent },
606     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
607     { 0 }
608 };
609 /* CreateWindow (for maximized child window, not initially visible) */
610 static const struct message WmCreateMaximizedChildSeq[] = {
611     { HCBT_CREATEWND, hook },
612     { WM_NCCREATE, sent }, 
613     { WM_NCCALCSIZE, sent|wparam, 0 },
614     { WM_CREATE, sent },
615     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
616     { WM_SIZE, sent|wparam, SIZE_RESTORED },
617     { WM_MOVE, sent },
618     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
619     { WM_GETMINMAXINFO, sent },
620     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
621     { WM_NCCALCSIZE, sent|wparam, 1 },
622     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|0x8000 },
623     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
624     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
625     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
626     { 0 }
627 };
628 /* CreateWindow (for a child window, initially visible) */
629 static const struct message WmCreateVisibleChildSeq[] = {
630     { HCBT_CREATEWND, hook },
631     { WM_NCCREATE, sent }, 
632     /* child is inserted into parent's child list after WM_NCCREATE returns */
633     { WM_NCCALCSIZE, sent|wparam, 0 },
634     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
635     { WM_CREATE, sent },
636     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
637     { WM_SIZE, sent|wparam, SIZE_RESTORED },
638     { WM_MOVE, sent },
639     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
640     { WM_SHOWWINDOW, sent|wparam, 1 },
641     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
642     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
643     { WM_ERASEBKGND, sent|parent|optional },
644     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
645     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */
646     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
647     { 0 }
648 };
649 /* ShowWindow(SW_SHOW) for a not visible child window */
650 static const struct message WmShowChildSeq[] = {
651     { WM_SHOWWINDOW, sent|wparam, 1 },
652     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
653     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
654     { WM_ERASEBKGND, sent|parent|optional },
655     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
656     { 0 }
657 };
658 /* ShowWindow(SW_HIDE) for a visible child window */
659 static const struct message WmHideChildSeq[] = {
660     { WM_SHOWWINDOW, sent|wparam, 0 },
661     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
662     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
663     { WM_ERASEBKGND, sent|parent|optional },
664     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
665     { 0 }
666 };
667 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
668  * for a not visible child window
669  */
670 static const struct message WmShowChildSeq_2[] = {
671     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
672     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
673     { WM_CHILDACTIVATE, sent },
674     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
675     { 0 }
676 };
677 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
678  * for a not visible child window
679  */
680 static const struct message WmShowChildSeq_3[] = {
681     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
682     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
683     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
684     { 0 }
685 };
686 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
687  * for a visible child window with a caption
688  */
689 static const struct message WmShowChildSeq_4[] = {
690     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
691     { WM_CHILDACTIVATE, sent },
692     { 0 }
693 };
694 /* ShowWindow(SW_MINIMIZE) for child with invisible parent */
695 static const struct message WmShowChildInvisibleParentSeq_1[] = {
696     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
697     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|0x8000 },
698     { WM_NCCALCSIZE, sent|wparam, 1 },
699     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|0x8000 },
700     { WM_MOVE, sent|defwinproc },
701     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
702     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
703     /* FIXME: Wine creates an icon/title window while Windows doesn't */
704     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
705     { WM_GETTEXT, sent|optional },
706     { 0 }
707 };
708 /* repeated ShowWindow(SW_MINIMIZE) for child with invisible parent */
709 static const struct message WmShowChildInvisibleParentSeq_1r[] = {
710     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
711     { 0 }
712 };
713 /* ShowWindow(SW_MAXIMIZE) for child with invisible parent */
714 static const struct message WmShowChildInvisibleParentSeq_2[] = {
715     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
716     { WM_GETMINMAXINFO, sent },
717     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
718     { WM_NCCALCSIZE, sent|wparam, 1 },
719     { WM_CHILDACTIVATE, sent },
720     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|0x8000 },
721     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
722     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
723     { 0 }
724 };
725 /* repeated ShowWindow(SW_MAXIMIZE) for child with invisible parent */
726 static const struct message WmShowChildInvisibleParentSeq_2r[] = {
727     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
728     { 0 }
729 };
730 /* ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
731 static const struct message WmShowChildInvisibleParentSeq_3[] = {
732     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
733     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
734     { WM_NCCALCSIZE, sent|wparam, 1 },
735     { WM_CHILDACTIVATE, sent },
736     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|0x8000 },
737     { WM_MOVE, sent|defwinproc },
738     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
739     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
740     /* FIXME: Wine creates an icon/title window while Windows doesn't */
741     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
742     { WM_GETTEXT, sent|optional },
743     { 0 }
744 };
745 /* repeated ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
746 static const struct message WmShowChildInvisibleParentSeq_3r[] = {
747     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
748     { 0 }
749 };
750 /* ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
751 static const struct message WmShowChildInvisibleParentSeq_4[] = {
752     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
753     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|0x8000 },
754     { WM_NCCALCSIZE, sent|wparam, 1 },
755     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|0x8000 },
756     { WM_MOVE, sent|defwinproc },
757     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
758     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
759     /* FIXME: Wine creates an icon/title window while Windows doesn't */
760     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
761     { WM_GETTEXT, sent|optional },
762     { 0 }
763 };
764 /* repeated ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
765 static const struct message WmShowChildInvisibleParentSeq_4r[] = {
766     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
767     { 0 }
768 };
769 /* ShowWindow(SW_SHOW) for child with invisible parent */
770 static const struct message WmShowChildInvisibleParentSeq_5[] = {
771     { WM_SHOWWINDOW, sent|wparam, 1 },
772     { 0 }
773 };
774 /* ShowWindow(SW_HIDE) for child with invisible parent */
775 static const struct message WmHideChildInvisibleParentSeq[] = {
776     { WM_SHOWWINDOW, sent|wparam, 0 },
777     { 0 }
778 };
779 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
780 static const struct message WmShowChildInvisibleParentSeq_6[] = {
781     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
782     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
783     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
784     { 0 }
785 };
786 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
787 static const struct message WmHideChildInvisibleParentSeq_2[] = {
788     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
789     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
790     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
791     { 0 }
792 };
793 /* DestroyWindow for a visible child window */
794 static const struct message WmDestroyChildSeq[] = {
795     { HCBT_DESTROYWND, hook },
796     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
797     { WM_SHOWWINDOW, sent|wparam, 0 },
798     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
799     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
800     { WM_ERASEBKGND, sent|parent|optional },
801     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
802     { HCBT_SETFOCUS, hook }, /* set focus to a parent */
803     { WM_KILLFOCUS, sent },
804     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
805     { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
806     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
807     { WM_SETFOCUS, sent|parent },
808     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
809     { WM_DESTROY, sent },
810     { WM_DESTROY, sent|optional }, /* some other (IME?) window */
811     { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
812     { WM_NCDESTROY, sent },
813     { 0 }
814 };
815 /* DestroyWindow for a visible child window with invisible parent */
816 static const struct message WmDestroyInvisibleChildSeq[] = {
817     { HCBT_DESTROYWND, hook },
818     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
819     { WM_SHOWWINDOW, sent|wparam, 0 },
820     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
821     { WM_DESTROY, sent },
822     { WM_NCDESTROY, sent },
823     { 0 }
824 };
825 /* Moving the mouse in nonclient area */
826 static const struct message WmMouseMoveInNonClientAreaSeq[] = { /* FIXME: add */
827     { WM_NCHITTEST, sent },
828     { WM_SETCURSOR, sent },
829     { WM_NCMOUSEMOVE, posted },
830     { 0 }
831 };
832 /* Moving the mouse in client area */
833 static const struct message WmMouseMoveInClientAreaSeq[] = { /* FIXME: add */
834     { WM_NCHITTEST, sent },
835     { WM_SETCURSOR, sent },
836     { WM_MOUSEMOVE, posted },
837     { 0 }
838 };
839 /* Moving by dragging the title bar (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
840 static const struct message WmDragTitleBarSeq[] = { /* FIXME: add */
841     { WM_NCLBUTTONDOWN, sent|wparam, HTCAPTION },
842     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_MOVE+2 },
843     { WM_GETMINMAXINFO, sent|defwinproc },
844     { WM_ENTERSIZEMOVE, sent|defwinproc },
845     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
846     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
847     { WM_MOVE, sent|defwinproc },
848     { WM_EXITSIZEMOVE, sent|defwinproc },
849     { 0 }
850 };
851 /* Sizing by dragging the thick borders (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
852 static const struct message WmDragThickBordersBarSeq[] = { /* FIXME: add */
853     { WM_NCLBUTTONDOWN, sent|wparam, 0xd },
854     { WM_SYSCOMMAND, sent|defwinproc|wparam, 0xf004 },
855     { WM_GETMINMAXINFO, sent|defwinproc },
856     { WM_ENTERSIZEMOVE, sent|defwinproc },
857     { WM_SIZING, sent|defwinproc|wparam, 4}, /* one for each mouse movement */
858     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
859     { WM_GETMINMAXINFO, sent|defwinproc },
860     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
861     { WM_NCPAINT, sent|defwinproc|wparam, 1 },
862     { WM_GETTEXT, sent|defwinproc },
863     { WM_ERASEBKGND, sent|defwinproc },
864     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
865     { WM_MOVE, sent|defwinproc },
866     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
867     { WM_EXITSIZEMOVE, sent|defwinproc },
868     { 0 }
869 };
870 /* Resizing child window with MoveWindow (32) */
871 static const struct message WmResizingChildWithMoveWindowSeq[] = {
872     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
873     { WM_NCCALCSIZE, sent|wparam, 1 },
874     { WM_ERASEBKGND, sent|optional },
875     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE },
876     { WM_MOVE, sent|defwinproc },
877     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
878     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
879     { 0 }
880 };
881 /* Clicking on inactive button */
882 static const struct message WmClickInactiveButtonSeq[] = { /* FIXME: add */
883     { WM_NCHITTEST, sent },
884     { WM_PARENTNOTIFY, sent|parent|wparam, WM_LBUTTONDOWN },
885     { WM_MOUSEACTIVATE, sent },
886     { WM_MOUSEACTIVATE, sent|parent|defwinproc },
887     { WM_SETCURSOR, sent },
888     { WM_SETCURSOR, sent|parent|defwinproc },
889     { WM_LBUTTONDOWN, posted },
890     { WM_KILLFOCUS, posted|parent },
891     { WM_SETFOCUS, posted },
892     { WM_CTLCOLORBTN, posted|parent },
893     { BM_SETSTATE, posted },
894     { WM_CTLCOLORBTN, posted|parent },
895     { WM_LBUTTONUP, posted },
896     { BM_SETSTATE, posted },
897     { WM_CTLCOLORBTN, posted|parent },
898     { WM_COMMAND, posted|parent },
899     { 0 }
900 };
901 /* Reparenting a button (16/32) */
902 /* The last child (button) reparented gets topmost for its new parent. */
903 static const struct message WmReparentButtonSeq[] = { /* FIXME: add */
904     { WM_SHOWWINDOW, sent|wparam, 0 },
905     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
906     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
907     { WM_ERASEBKGND, sent|parent },
908     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
909     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
910     { WM_CHILDACTIVATE, sent },
911     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW },
912     { WM_MOVE, sent|defwinproc },
913     { WM_SHOWWINDOW, sent|wparam, 1 },
914     { 0 }
915 };
916 /* Creation of a custom dialog (32) */
917 static const struct message WmCreateCustomDialogSeq[] = {
918     { HCBT_CREATEWND, hook },
919     { WM_GETMINMAXINFO, sent },
920     { WM_NCCREATE, sent },
921     { WM_NCCALCSIZE, sent|wparam, 0 },
922     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
923     { WM_CREATE, sent },
924     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
925     { WM_SHOWWINDOW, sent|wparam, 1 },
926     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
927     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
928     { HCBT_ACTIVATE, hook },
929     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
930
931
932     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
933
934     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
935
936     { WM_NCACTIVATE, sent|wparam, 1 },
937     { WM_GETTEXT, sent|optional|defwinproc },
938     { WM_GETTEXT, sent|optional|defwinproc },
939     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
940     { WM_ACTIVATE, sent|wparam, 1 },
941     { WM_KILLFOCUS, sent|parent },
942     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
943     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
944     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
945     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
946     { WM_SETFOCUS, sent },
947     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
948     { WM_NCPAINT, sent|wparam, 1 },
949     { WM_GETTEXT, sent|optional|defwinproc },
950     { WM_GETTEXT, sent|optional|defwinproc },
951     { WM_ERASEBKGND, sent },
952     { WM_CTLCOLORDLG, sent|defwinproc },
953     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
954     { WM_GETTEXT, sent|optional },
955     { WM_GETTEXT, sent|optional },
956     { WM_NCCALCSIZE, sent|optional },
957     { WM_NCPAINT, sent|optional },
958     { WM_GETTEXT, sent|optional|defwinproc },
959     { WM_GETTEXT, sent|optional|defwinproc },
960     { WM_ERASEBKGND, sent|optional },
961     { WM_CTLCOLORDLG, sent|optional|defwinproc },
962     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
963     { WM_SIZE, sent|wparam, SIZE_RESTORED },
964     { WM_MOVE, sent },
965     { 0 }
966 };
967 /* Calling EndDialog for a custom dialog (32) */
968 static const struct message WmEndCustomDialogSeq[] = {
969     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
970     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
971     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
972     { WM_GETTEXT, sent|optional },
973     { HCBT_ACTIVATE, hook },
974     { WM_NCACTIVATE, sent|wparam, 0 },
975     { WM_GETTEXT, sent|optional|defwinproc },
976     { WM_GETTEXT, sent|optional|defwinproc },
977     { WM_ACTIVATE, sent|wparam, 0 },
978     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
979     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
980     { HCBT_SETFOCUS, hook },
981     { WM_KILLFOCUS, sent },
982     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
983     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
984     { WM_IME_NOTIFY, sent|wparam|optional, 1 },
985     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
986     { WM_SETFOCUS, sent|parent|defwinproc },
987     { 0 }
988 };
989 /* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
990 static const struct message WmShowCustomDialogSeq[] = {
991     { WM_SHOWWINDOW, sent|wparam, 1 },
992     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
993     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
994     { HCBT_ACTIVATE, hook },
995     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
996
997     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
998
999     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1000     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
1001     { WM_NCACTIVATE, sent|wparam, 1 },
1002     { WM_ACTIVATE, sent|wparam, 1 },
1003
1004     { WM_KILLFOCUS, sent|parent },
1005     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1006     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1007     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1008     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1009     { WM_SETFOCUS, sent },
1010     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1011     { WM_NCPAINT, sent|wparam, 1 },
1012     { WM_ERASEBKGND, sent },
1013     { WM_CTLCOLORDLG, sent|defwinproc },
1014     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1015     { 0 }
1016 };
1017 /* Creation and destruction of a modal dialog (32) */
1018 static const struct message WmModalDialogSeq[] = {
1019     { WM_CANCELMODE, sent|parent },
1020     { HCBT_SETFOCUS, hook },
1021     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1022     { WM_KILLFOCUS, sent|parent },
1023     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1024     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1025     { WM_ENABLE, sent|parent|wparam, 0 },
1026     { HCBT_CREATEWND, hook },
1027     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1028     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1029     { WM_SETFONT, sent },
1030     { WM_INITDIALOG, sent },
1031     { WM_CHANGEUISTATE, sent|optional },
1032     { WM_UPDATEUISTATE, sent|optional },
1033     { WM_SHOWWINDOW, sent },
1034     { HCBT_ACTIVATE, hook },
1035     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1036     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1037     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1038     { WM_NCACTIVATE, sent|wparam, 1 },
1039     { WM_GETTEXT, sent|optional },
1040     { WM_ACTIVATE, sent|wparam, 1 },
1041     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1042     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1043     { WM_NCPAINT, sent },
1044     { WM_GETTEXT, sent|optional },
1045     { WM_ERASEBKGND, sent },
1046     { WM_CTLCOLORDLG, sent },
1047     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1048     { WM_GETTEXT, sent|optional },
1049     { WM_NCCALCSIZE, sent|optional },
1050     { WM_NCPAINT, sent|optional },
1051     { WM_GETTEXT, sent|optional },
1052     { WM_ERASEBKGND, sent|optional },
1053     { WM_CTLCOLORDLG, sent|optional },
1054     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1055     { WM_PAINT, sent|optional },
1056     { WM_CTLCOLORBTN, sent },
1057     { WM_ENTERIDLE, sent|parent|optional },
1058     { WM_ENTERIDLE, sent|parent|optional },
1059     { WM_ENTERIDLE, sent|parent|optional },
1060     { WM_ENTERIDLE, sent|parent|optional },
1061     { WM_ENTERIDLE, sent|parent|optional },
1062     { WM_ENTERIDLE, sent|parent|optional },
1063     { WM_ENTERIDLE, sent|parent|optional },
1064     { WM_ENTERIDLE, sent|parent|optional },
1065     { WM_ENTERIDLE, sent|parent|optional },
1066     { WM_ENTERIDLE, sent|parent|optional },
1067     { WM_ENTERIDLE, sent|parent|optional },
1068     { WM_ENTERIDLE, sent|parent|optional },
1069     { WM_ENTERIDLE, sent|parent|optional },
1070     { WM_ENTERIDLE, sent|parent|optional },
1071     { WM_ENTERIDLE, sent|parent|optional },
1072     { WM_ENTERIDLE, sent|parent|optional },
1073     { WM_ENTERIDLE, sent|parent|optional },
1074     { WM_ENTERIDLE, sent|parent|optional },
1075     { WM_ENTERIDLE, sent|parent|optional },
1076     { WM_ENTERIDLE, sent|parent|optional },
1077     { WM_TIMER, sent },
1078     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1079     { WM_ENABLE, sent|parent|wparam, 1 },
1080     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1081     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1082     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1083     { WM_GETTEXT, sent|optional },
1084     { HCBT_ACTIVATE, hook },
1085     { WM_NCACTIVATE, sent|wparam, 0 },
1086     { WM_GETTEXT, sent|optional },
1087     { WM_ACTIVATE, sent|wparam, 0 },
1088     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1089     { WM_WINDOWPOSCHANGING, sent|optional },
1090     { HCBT_SETFOCUS, hook },
1091     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1092     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1093     { WM_SETFOCUS, sent|parent|defwinproc },
1094     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 },
1095     { HCBT_DESTROYWND, hook },
1096     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1097     { WM_DESTROY, sent },
1098     { WM_NCDESTROY, sent },
1099     { 0 }
1100 };
1101 /* Creation of a modal dialog that is resized inside WM_INITDIALOG (32) */
1102 static const struct message WmCreateModalDialogResizeSeq[] = { /* FIXME: add */
1103     /* (inside dialog proc, handling WM_INITDIALOG) */
1104     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1105     { WM_NCCALCSIZE, sent },
1106     { WM_NCACTIVATE, sent|parent|wparam, 0 },
1107     { WM_GETTEXT, sent|defwinproc },
1108     { WM_ACTIVATE, sent|parent|wparam, 0 },
1109     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1110     { WM_WINDOWPOSCHANGING, sent|parent },
1111     { WM_NCACTIVATE, sent|wparam, 1 },
1112     { WM_ACTIVATE, sent|wparam, 1 },
1113     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1114     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1115     /* (setting focus) */
1116     { WM_SHOWWINDOW, sent|wparam, 1 },
1117     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1118     { WM_NCPAINT, sent },
1119     { WM_GETTEXT, sent|defwinproc },
1120     { WM_ERASEBKGND, sent },
1121     { WM_CTLCOLORDLG, sent|defwinproc },
1122     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1123     { WM_PAINT, sent },
1124     /* (bunch of WM_CTLCOLOR* for each control) */
1125     { WM_PAINT, sent|parent },
1126     { WM_ENTERIDLE, sent|parent|wparam, 0 },
1127     { WM_SETCURSOR, sent|parent },
1128     { 0 }
1129 };
1130 /* SetMenu for NonVisible windows with size change*/
1131 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
1132     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1133     { WM_NCCALCSIZE, sent|wparam, 1 },
1134     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1135     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
1136     { WM_MOVE, sent|defwinproc },
1137     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1138     { WM_NCCALCSIZE,sent|wparam|optional, 1 }, /* XP */
1139     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1140     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1141     { WM_GETTEXT, sent|optional },
1142     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1143     { 0 }
1144 };
1145 /* SetMenu for NonVisible windows with no size change */
1146 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
1147     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1148     { WM_NCCALCSIZE, sent|wparam, 1 },
1149     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1150     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1151     { 0 }
1152 };
1153 /* SetMenu for Visible windows with size change */
1154 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
1155     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1156     { WM_NCCALCSIZE, sent|wparam, 1 },
1157     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1158     { WM_NCPAINT, sent }, /* wparam != 1 */
1159     { WM_GETTEXT, sent|defwinproc|optional },
1160     { WM_ERASEBKGND, sent|optional },
1161     { WM_ACTIVATE, sent|optional },
1162     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1163     { WM_MOVE, sent|defwinproc },
1164     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1165     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1166     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1167     { WM_ERASEBKGND, sent|optional },
1168     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1169     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1170     { 0 }
1171 };
1172 /* SetMenu for Visible windows with no size change */
1173 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
1174     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1175     { WM_NCCALCSIZE, sent|wparam, 1 },
1176     { WM_NCPAINT, sent }, /* wparam != 1 */
1177     { WM_GETTEXT, sent|defwinproc|optional },
1178     { WM_ERASEBKGND, sent|optional },
1179     { WM_ACTIVATE, sent|optional },
1180     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1181     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1182     { 0 }
1183 };
1184 /* DrawMenuBar for a visible window */
1185 static const struct message WmDrawMenuBarSeq[] =
1186 {
1187     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1188     { WM_NCCALCSIZE, sent|wparam, 1 },
1189     { WM_NCPAINT, sent }, /* wparam != 1 */
1190     { WM_GETTEXT, sent|defwinproc|optional },
1191     { WM_ERASEBKGND, sent|optional },
1192     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1193     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1194     { 0 }
1195 };
1196
1197 static const struct message WmSetRedrawFalseSeq[] =
1198 {
1199     { WM_SETREDRAW, sent|wparam, 0 },
1200     { 0 }
1201 };
1202
1203 static const struct message WmSetRedrawTrueSeq[] =
1204 {
1205     { WM_SETREDRAW, sent|wparam, 1 },
1206     { 0 }
1207 };
1208
1209 static const struct message WmEnableWindowSeq_1[] =
1210 {
1211     { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1212     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1213     { WM_ENABLE, sent|wparam|lparam, FALSE, 0 },
1214     { 0 }
1215 };
1216
1217 static const struct message WmEnableWindowSeq_2[] =
1218 {
1219     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1220     { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
1221     { 0 }
1222 };
1223
1224 static const struct message WmGetScrollRangeSeq[] =
1225 {
1226     { SBM_GETRANGE, sent },
1227     { 0 }
1228 };
1229 static const struct message WmGetScrollInfoSeq[] =
1230 {
1231     { SBM_GETSCROLLINFO, sent },
1232     { 0 }
1233 };
1234 static const struct message WmSetScrollRangeSeq[] =
1235 {
1236     /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
1237        sends SBM_SETSCROLLINFO.
1238      */
1239     { SBM_SETSCROLLINFO, sent },
1240     { 0 }
1241 };
1242 /* SetScrollRange for a window without a non-client area */
1243 static const struct message WmSetScrollRangeHSeq_empty[] =
1244 {
1245     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_HSCROLL, 0 },
1246     { 0 }
1247 };
1248 static const struct message WmSetScrollRangeVSeq_empty[] =
1249 {
1250     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_VSCROLL, 0 },
1251     { 0 }
1252 };
1253 static const struct message WmSetScrollRangeHVSeq[] =
1254 {
1255     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1256     { WM_NCCALCSIZE, sent|wparam, 1 },
1257     { WM_GETTEXT, sent|defwinproc|optional },
1258     { WM_ERASEBKGND, sent|optional },
1259     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1260     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1261     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1262     { 0 }
1263 };
1264 /* SetScrollRange for a window with a non-client area */
1265 static const struct message WmSetScrollRangeHV_NC_Seq[] =
1266 {
1267     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1268     { WM_NCCALCSIZE, sent|wparam, 1 },
1269     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1270     { WM_NCPAINT, sent|optional },
1271     { WM_GETTEXT, sent|defwinproc|optional },
1272     { WM_GETTEXT, sent|defwinproc|optional },
1273     { WM_ERASEBKGND, sent|optional },
1274     { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
1275     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE },
1276     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1277     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1278     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1279     { WM_GETTEXT, sent|optional },
1280     { WM_GETTEXT, sent|optional },
1281     { WM_GETTEXT, sent|optional },
1282     { WM_GETTEXT, sent|optional },
1283     { 0 }
1284 };
1285 /* test if we receive the right sequence of messages */
1286 /* after calling ShowWindow( SW_SHOWNA) */
1287 static const struct message WmSHOWNAChildInvisParInvis[] = {
1288     { WM_SHOWWINDOW, sent|wparam, 1 },
1289     { 0 }
1290 };
1291 static const struct message WmSHOWNAChildVisParInvis[] = {
1292     { WM_SHOWWINDOW, sent|wparam, 1 },
1293     { 0 }
1294 };
1295 static const struct message WmSHOWNAChildVisParVis[] = {
1296     { WM_SHOWWINDOW, sent|wparam, 1 },
1297     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1298     { 0 }
1299 };
1300 static const struct message WmSHOWNAChildInvisParVis[] = {
1301     { WM_SHOWWINDOW, sent|wparam, 1 },
1302     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1303     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1304     { WM_ERASEBKGND, sent|optional },
1305     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOCLIENTMOVE },
1306     { 0 }
1307 };
1308 static const struct message WmSHOWNATopVisible[] = {
1309     { WM_SHOWWINDOW, sent|wparam, 1 },
1310     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1311     { 0 }
1312 };
1313 static const struct message WmSHOWNATopInvisible[] = {
1314     { WM_SHOWWINDOW, sent|wparam, 1 },
1315     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1316     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1317     { WM_NCPAINT, sent|wparam, 1 },
1318     { WM_GETTEXT, sent|defwinproc|optional },
1319     { WM_ERASEBKGND, sent|optional },
1320     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1321     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1322     { WM_NCPAINT, sent|wparam|optional, 1 },
1323     { WM_ERASEBKGND, sent|optional },
1324     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1325     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1326     { WM_MOVE, sent },
1327     { 0 }
1328 };
1329
1330 static int after_end_dialog, test_def_id;
1331 static int sequence_cnt, sequence_size;
1332 static struct message* sequence;
1333 static int log_all_parent_messages;
1334
1335 static void add_message(const struct message *msg)
1336 {
1337     if (!sequence) 
1338     {
1339         sequence_size = 10;
1340         sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof (struct message) );
1341     }
1342     if (sequence_cnt == sequence_size) 
1343     {
1344         sequence_size *= 2;
1345         sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof (struct message) );
1346     }
1347     assert(sequence);
1348
1349     sequence[sequence_cnt].message = msg->message;
1350     sequence[sequence_cnt].flags = msg->flags;
1351     sequence[sequence_cnt].wParam = msg->wParam;
1352     sequence[sequence_cnt].lParam = msg->lParam;
1353
1354     sequence_cnt++;
1355 }
1356
1357 /* try to make sure pending X events have been processed before continuing */
1358 static void flush_events(void)
1359 {
1360     MSG msg;
1361     int diff = 100;
1362     DWORD time = GetTickCount() + diff;
1363
1364     while (diff > 0)
1365     {
1366         MsgWaitForMultipleObjects( 0, NULL, FALSE, diff, QS_ALLINPUT );
1367         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
1368         diff = time - GetTickCount();
1369     }
1370 }
1371
1372 static void flush_sequence(void)
1373 {
1374     HeapFree(GetProcessHeap(), 0, sequence);
1375     sequence = 0;
1376     sequence_cnt = sequence_size = 0;
1377 }
1378
1379 #define ok_sequence( exp, contx, todo) \
1380         ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
1381
1382
1383 static void ok_sequence_(const struct message *expected, const char *context, int todo,
1384         const char *file, int line)
1385 {
1386     static const struct message end_of_sequence = { 0, 0, 0, 0 };
1387     const struct message *actual;
1388     int failcount = 0;
1389     
1390     add_message(&end_of_sequence);
1391
1392     actual = sequence;
1393
1394     while (expected->message && actual->message)
1395     {
1396         trace_( file, line)("expected %04x - actual %04x\n", expected->message, actual->message);
1397
1398         if (expected->message == actual->message)
1399         {
1400             if (expected->flags & wparam)
1401             {
1402                 if (expected->wParam != actual->wParam && todo)
1403                 {
1404                     todo_wine {
1405                         failcount ++;
1406                         ok_( file, line) (FALSE,
1407                             "%s: in msg 0x%04x expecting wParam 0x%x got 0x%x\n",
1408                             context, expected->message, expected->wParam, actual->wParam);
1409                     }
1410                 }
1411                 else
1412                 ok_( file, line) (expected->wParam == actual->wParam,
1413                      "%s: in msg 0x%04x expecting wParam 0x%x got 0x%x\n",
1414                      context, expected->message, expected->wParam, actual->wParam);
1415             }
1416             if (expected->flags & lparam)
1417             {
1418                 if (expected->lParam != actual->lParam && todo)
1419                 {
1420                     todo_wine {
1421                         failcount ++;
1422                         ok_( file, line) (FALSE,
1423                             "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
1424                             context, expected->message, expected->lParam, actual->lParam);
1425                     }
1426                 }
1427                 else
1428                  ok_( file, line) (expected->lParam == actual->lParam,
1429                      "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
1430                      context, expected->message, expected->lParam, actual->lParam);
1431             }
1432             if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
1433             {
1434                     todo_wine {
1435                         failcount ++;
1436                         ok_( file, line) (FALSE,
1437                             "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
1438                             context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
1439                     }
1440             }
1441             else
1442                 ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
1443                     "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
1444                     context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
1445             ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
1446                 "%s: the msg 0x%04x should %shave been sent by BeginPaint\n",
1447                 context, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
1448             ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
1449                 "%s: the msg 0x%04x should have been %s\n",
1450                 context, expected->message, (expected->flags & posted) ? "posted" : "sent");
1451             ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
1452                 "%s: the msg 0x%04x was expected in %s\n",
1453                 context, expected->message, (expected->flags & parent) ? "parent" : "child");
1454             ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
1455                 "%s: the msg 0x%04x should have been sent by a hook\n",
1456                 context, expected->message);
1457             ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
1458                 "%s: the msg 0x%04x should have been sent by a winevent hook\n",
1459                 context, expected->message);
1460             expected++;
1461             actual++;
1462         }
1463         /* silently drop winevent messages if there is no support for them */
1464         else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
1465             expected++;
1466         else if (todo)
1467         {
1468             failcount++;
1469             todo_wine {
1470                 ok_( file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
1471                     context, expected->message, actual->message);
1472             }
1473             flush_sequence();
1474             return;
1475         }
1476         else
1477         {
1478             ok_( file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
1479                 context, expected->message, actual->message);
1480             expected++;
1481             actual++;
1482         }
1483     }
1484
1485     /* skip all optional trailing messages */
1486     while (expected->message && ((expected->flags & optional) ||
1487             ((expected->flags & winevent_hook) && !hEvent_hook)))
1488         expected++;
1489
1490     if (todo)
1491     {
1492         todo_wine {
1493             if (expected->message || actual->message) {
1494                 failcount++;
1495                 ok_( file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
1496                     context, expected->message, actual->message);
1497             }
1498         }
1499     }
1500     else
1501     {
1502         if (expected->message || actual->message)
1503             ok_( file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
1504                 context, expected->message, actual->message);
1505     }
1506     if( todo && !failcount) /* succeeded yet marked todo */
1507         todo_wine {
1508             ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
1509         }
1510
1511     flush_sequence();
1512 }
1513
1514 /******************************** MDI test **********************************/
1515
1516 /* CreateWindow for MDI frame window, initially visible */
1517 static const struct message WmCreateMDIframeSeq[] = {
1518     { HCBT_CREATEWND, hook },
1519     { WM_GETMINMAXINFO, sent },
1520     { WM_NCCREATE, sent },
1521     { WM_NCCALCSIZE, sent|wparam, 0 },
1522     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1523     { WM_CREATE, sent },
1524     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1525     { WM_SHOWWINDOW, sent|wparam, 1 },
1526     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1527     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1528     { HCBT_ACTIVATE, hook },
1529     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1530     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1531     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
1532     { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
1533     { WM_NCACTIVATE, sent|wparam, 1 },
1534     { WM_GETTEXT, sent|defwinproc|optional },
1535     { WM_ACTIVATE, sent|wparam, 1 },
1536     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
1537     { HCBT_SETFOCUS, hook },
1538     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1539     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1540     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1541     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
1542     /* Win9x adds SWP_NOZORDER below */
1543     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1544     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
1545     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1546     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1547     { WM_MOVE, sent },
1548     { 0 }
1549 };
1550 /* DestroyWindow for MDI frame window, initially visible */
1551 static const struct message WmDestroyMDIframeSeq[] = {
1552     { HCBT_DESTROYWND, hook },
1553     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1554     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1555     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
1556     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1557     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
1558     { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
1559     { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
1560     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
1561     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1562     { WM_DESTROY, sent },
1563     { WM_NCDESTROY, sent },
1564     { 0 }
1565 };
1566 /* CreateWindow for MDI client window, initially visible */
1567 static const struct message WmCreateMDIclientSeq[] = {
1568     { HCBT_CREATEWND, hook },
1569     { WM_NCCREATE, sent },
1570     { WM_NCCALCSIZE, sent|wparam, 0 },
1571     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
1572     { WM_CREATE, sent },
1573     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
1574     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1575     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1576     { WM_MOVE, sent },
1577     { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
1578     { WM_SHOWWINDOW, sent|wparam, 1 },
1579     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1580     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1581     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1582     { 0 }
1583 };
1584 /* ShowWindow(SW_SHOW) for MDI client window */
1585 static const struct message WmShowMDIclientSeq[] = {
1586     { WM_SHOWWINDOW, sent|wparam, 1 },
1587     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1588     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1589     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1590     { 0 }
1591 };
1592 /* ShowWindow(SW_HIDE) for MDI client window */
1593 static const struct message WmHideMDIclientSeq[] = {
1594     { WM_SHOWWINDOW, sent|wparam, 0 },
1595     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1596     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
1597     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
1598     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1599     { 0 }
1600 };
1601 /* DestroyWindow for MDI client window, initially visible */
1602 static const struct message WmDestroyMDIclientSeq[] = {
1603     { HCBT_DESTROYWND, hook },
1604     { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
1605     { WM_SHOWWINDOW, sent|wparam, 0 },
1606     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1607     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1608     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1609     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1610     { WM_DESTROY, sent },
1611     { WM_NCDESTROY, sent },
1612     { 0 }
1613 };
1614 /* CreateWindow for MDI child window, initially visible */
1615 static const struct message WmCreateMDIchildVisibleSeq[] = {
1616     { HCBT_CREATEWND, hook },
1617     { WM_NCCREATE, sent }, 
1618     { WM_NCCALCSIZE, sent|wparam, 0 },
1619     { WM_CREATE, sent },
1620     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1621     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1622     { WM_MOVE, sent },
1623     /* Win2k sends wparam set to
1624      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1625      * while Win9x doesn't bother to set child window id according to
1626      * CLIENTCREATESTRUCT.idFirstChild
1627      */
1628     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1629     { WM_SHOWWINDOW, sent|wparam, 1 },
1630     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1631     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1632     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1633     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1634     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1635     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1636     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1637
1638     /* Win9x: message sequence terminates here. */
1639
1640     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1641     { HCBT_SETFOCUS, hook }, /* in MDI client */
1642     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1643     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
1644     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1645     { WM_SETFOCUS, sent }, /* in MDI client */
1646     { HCBT_SETFOCUS, hook },
1647     { WM_KILLFOCUS, sent }, /* in MDI client */
1648     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1649     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1650     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1651     { WM_SETFOCUS, sent|defwinproc },
1652     { WM_MDIACTIVATE, sent|defwinproc },
1653     { 0 }
1654 };
1655 /* CreateWindow for MDI child window with invisible parent */
1656 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
1657     { HCBT_CREATEWND, hook },
1658     { WM_GETMINMAXINFO, sent },
1659     { WM_NCCREATE, sent }, 
1660     { WM_NCCALCSIZE, sent|wparam, 0 },
1661     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
1662     { WM_CREATE, sent },
1663     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1664     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1665     { WM_MOVE, sent },
1666     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1667     { WM_SHOWWINDOW, sent|wparam, 1 },
1668     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
1669     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1670     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1671     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1672
1673     /* Win9x: message sequence terminates here. */
1674
1675     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1676     { HCBT_SETFOCUS, hook }, /* in MDI client */
1677     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1678     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
1679     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1680     { WM_SETFOCUS, sent }, /* in MDI client */
1681     { HCBT_SETFOCUS, hook },
1682     { WM_KILLFOCUS, sent }, /* in MDI client */
1683     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1684     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1685     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1686     { WM_SETFOCUS, sent|defwinproc },
1687     { WM_MDIACTIVATE, sent|defwinproc },
1688     { 0 }
1689 };
1690 /* DestroyWindow for MDI child window, initially visible */
1691 static const struct message WmDestroyMDIchildVisibleSeq[] = {
1692     { HCBT_DESTROYWND, hook },
1693     /* Win2k sends wparam set to
1694      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1695      * while Win9x doesn't bother to set child window id according to
1696      * CLIENTCREATESTRUCT.idFirstChild
1697      */
1698     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1699     { WM_SHOWWINDOW, sent|wparam, 0 },
1700     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1701     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1702     { WM_ERASEBKGND, sent|parent|optional },
1703     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1704
1705     /* { WM_DESTROY, sent }
1706      * Win9x: message sequence terminates here.
1707      */
1708
1709     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1710     { WM_KILLFOCUS, sent },
1711     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1712     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1713     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1714     { WM_SETFOCUS, sent }, /* in MDI client */
1715
1716     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1717     { WM_KILLFOCUS, sent }, /* in MDI client */
1718     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1719     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1720     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1721     { WM_SETFOCUS, sent }, /* in MDI client */
1722
1723     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1724
1725     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1726     { WM_KILLFOCUS, sent },
1727     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1728     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1729     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1730     { WM_SETFOCUS, sent }, /* in MDI client */
1731
1732     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1733     { WM_KILLFOCUS, sent }, /* in MDI client */
1734     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1735     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1736     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1737     { WM_SETFOCUS, sent }, /* in MDI client */
1738
1739     { WM_DESTROY, sent },
1740
1741     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1742     { WM_KILLFOCUS, sent },
1743     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1744     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1745     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1746     { WM_SETFOCUS, sent }, /* in MDI client */
1747
1748     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1749     { WM_KILLFOCUS, sent }, /* in MDI client */
1750     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1751     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1752     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1753     { WM_SETFOCUS, sent }, /* in MDI client */
1754
1755     { WM_NCDESTROY, sent },
1756     { 0 }
1757 };
1758 /* CreateWindow for MDI child window, initially invisible */
1759 static const struct message WmCreateMDIchildInvisibleSeq[] = {
1760     { HCBT_CREATEWND, hook },
1761     { WM_NCCREATE, sent }, 
1762     { WM_NCCALCSIZE, sent|wparam, 0 },
1763     { WM_CREATE, sent },
1764     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1765     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1766     { WM_MOVE, sent },
1767     /* Win2k sends wparam set to
1768      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1769      * while Win9x doesn't bother to set child window id according to
1770      * CLIENTCREATESTRUCT.idFirstChild
1771      */
1772     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1773     { 0 }
1774 };
1775 /* DestroyWindow for MDI child window, initially invisible */
1776 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
1777     { HCBT_DESTROYWND, hook },
1778     /* Win2k sends wparam set to
1779      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1780      * while Win9x doesn't bother to set child window id according to
1781      * CLIENTCREATESTRUCT.idFirstChild
1782      */
1783     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1784     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1785     { WM_DESTROY, sent },
1786     { WM_NCDESTROY, sent },
1787     /* FIXME: Wine destroys an icon/title window while Windows doesn't */
1788     { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */
1789     { 0 }
1790 };
1791 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
1792 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
1793     { HCBT_CREATEWND, hook },
1794     { WM_NCCREATE, sent }, 
1795     { WM_NCCALCSIZE, sent|wparam, 0 },
1796     { WM_CREATE, sent },
1797     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1798     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1799     { WM_MOVE, sent },
1800     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1801     { WM_GETMINMAXINFO, sent },
1802     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
1803     { WM_NCCALCSIZE, sent|wparam, 1 },
1804     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1805     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1806      /* in MDI frame */
1807     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1808     { WM_NCCALCSIZE, sent|wparam, 1 },
1809     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1810     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1811     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
1812     /* Win2k sends wparam set to
1813      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1814      * while Win9x doesn't bother to set child window id according to
1815      * CLIENTCREATESTRUCT.idFirstChild
1816      */
1817     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1818     { WM_SHOWWINDOW, sent|wparam, 1 },
1819     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1820     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1821     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1822     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1823     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1824     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1825     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1826
1827     /* Win9x: message sequence terminates here. */
1828
1829     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1830     { HCBT_SETFOCUS, hook }, /* in MDI client */
1831     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1832     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
1833     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1834     { WM_SETFOCUS, sent }, /* in MDI client */
1835     { HCBT_SETFOCUS, hook },
1836     { WM_KILLFOCUS, sent }, /* in MDI client */
1837     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1838     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1839     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1840     { WM_SETFOCUS, sent|defwinproc },
1841     { WM_MDIACTIVATE, sent|defwinproc },
1842      /* in MDI frame */
1843     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1844     { WM_NCCALCSIZE, sent|wparam, 1 },
1845     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1846     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1847     { 0 }
1848 };
1849 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
1850 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
1851     /* restore the 1st MDI child */
1852     { WM_SETREDRAW, sent|wparam, 0 },
1853     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
1854     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
1855     { WM_NCCALCSIZE, sent|wparam, 1 },
1856     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1857     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1858     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1859      /* in MDI frame */
1860     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1861     { WM_NCCALCSIZE, sent|wparam, 1 },
1862     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1863     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1864     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
1865     { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
1866     /* create the 2nd MDI child */
1867     { HCBT_CREATEWND, hook },
1868     { WM_NCCREATE, sent }, 
1869     { WM_NCCALCSIZE, sent|wparam, 0 },
1870     { WM_CREATE, sent },
1871     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1872     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1873     { WM_MOVE, sent },
1874     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1875     { WM_GETMINMAXINFO, sent },
1876     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
1877     { WM_NCCALCSIZE, sent|wparam, 1 },
1878     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1879     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1880     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1881      /* in MDI frame */
1882     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1883     { WM_NCCALCSIZE, sent|wparam, 1 },
1884     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1885     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1886     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
1887     /* Win2k sends wparam set to
1888      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1889      * while Win9x doesn't bother to set child window id according to
1890      * CLIENTCREATESTRUCT.idFirstChild
1891      */
1892     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1893     { WM_SHOWWINDOW, sent|wparam, 1 },
1894     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1895     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1896     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1897     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1898     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1899     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1900
1901     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
1902     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
1903
1904     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1905
1906     /* Win9x: message sequence terminates here. */
1907
1908     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1909     { HCBT_SETFOCUS, hook },
1910     { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
1911     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
1912     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1913     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1914     { WM_SETFOCUS, sent }, /* in MDI client */
1915     { HCBT_SETFOCUS, hook },
1916     { WM_KILLFOCUS, sent }, /* in MDI client */
1917     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1918     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1919     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1920     { WM_SETFOCUS, sent|defwinproc },
1921
1922     { WM_MDIACTIVATE, sent|defwinproc },
1923      /* in MDI frame */
1924     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1925     { WM_NCCALCSIZE, sent|wparam, 1 },
1926     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1927     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1928     { 0 }
1929 };
1930 /* WM_MDICREATE MDI child window, initially visible and maximized */
1931 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
1932     { WM_MDICREATE, sent },
1933     { HCBT_CREATEWND, hook },
1934     { WM_NCCREATE, sent }, 
1935     { WM_NCCALCSIZE, sent|wparam, 0 },
1936     { WM_CREATE, sent },
1937     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1938     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1939     { WM_MOVE, sent },
1940     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1941     { WM_GETMINMAXINFO, sent },
1942     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
1943     { WM_NCCALCSIZE, sent|wparam, 1 },
1944     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1945     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1946
1947      /* in MDI frame */
1948     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1949     { WM_NCCALCSIZE, sent|wparam, 1 },
1950     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1951     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1952     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
1953
1954     /* Win2k sends wparam set to
1955      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1956      * while Win9x doesn't bother to set child window id according to
1957      * CLIENTCREATESTRUCT.idFirstChild
1958      */
1959     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1960     { WM_SHOWWINDOW, sent|wparam, 1 },
1961     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1962
1963     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1964
1965     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1966     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1967     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1968
1969     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1970     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1971
1972     /* Win9x: message sequence terminates here. */
1973
1974     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1975     { WM_SETFOCUS, sent|optional }, /* in MDI client */
1976     { HCBT_SETFOCUS, hook }, /* in MDI client */
1977     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1978     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
1979     { WM_SETFOCUS, sent|optional }, /* in MDI client */
1980     { HCBT_SETFOCUS, hook|optional },
1981     { WM_KILLFOCUS, sent }, /* in MDI client */
1982     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1983     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1984     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1985     { WM_SETFOCUS, sent|defwinproc },
1986
1987     { WM_MDIACTIVATE, sent|defwinproc },
1988
1989      /* in MDI child */
1990     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1991     { WM_NCCALCSIZE, sent|wparam, 1 },
1992     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1993     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1994
1995      /* in MDI frame */
1996     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1997     { WM_NCCALCSIZE, sent|wparam, 1 },
1998     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1999     { WM_MOVE, sent|defwinproc },
2000     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2001
2002      /* in MDI client */
2003     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2004     { WM_NCCALCSIZE, sent|wparam, 1 },
2005     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2006     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2007
2008      /* in MDI child */
2009     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2010     { WM_NCCALCSIZE, sent|wparam, 1 },
2011     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2012     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2013
2014     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2015     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2016     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
2017     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2018     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2019
2020     { 0 }
2021 };
2022 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
2023 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
2024     { HCBT_CREATEWND, hook },
2025     { WM_GETMINMAXINFO, sent },
2026     { WM_NCCREATE, sent }, 
2027     { WM_NCCALCSIZE, sent|wparam, 0 },
2028     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2029     { WM_CREATE, sent },
2030     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2031     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2032     { WM_MOVE, sent },
2033     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2034     { WM_GETMINMAXINFO, sent },
2035     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
2036     { WM_GETMINMAXINFO, sent|defwinproc },
2037     { WM_NCCALCSIZE, sent|wparam, 1 },
2038     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|0x8000 },
2039     { WM_MOVE, sent|defwinproc },
2040     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2041      /* in MDI frame */
2042     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2043     { WM_NCCALCSIZE, sent|wparam, 1 },
2044     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2045     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2046     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
2047     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2048     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2049     /* Win2k sends wparam set to
2050      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2051      * while Win9x doesn't bother to set child window id according to
2052      * CLIENTCREATESTRUCT.idFirstChild
2053      */
2054     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2055     { 0 }
2056 };
2057 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
2058 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
2059     { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
2060     { HCBT_SYSCOMMAND, hook },
2061     { WM_CLOSE, sent|defwinproc },
2062     { WM_MDIDESTROY, sent }, /* in MDI client */
2063
2064     /* bring the 1st MDI child to top */
2065     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
2066     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
2067
2068     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2069
2070     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
2071     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2072     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2073
2074     /* maximize the 1st MDI child */
2075     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2076     { WM_GETMINMAXINFO, sent|defwinproc },
2077     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|0x8000 },
2078     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2079     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
2080     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2081     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2082
2083     /* restore the 2nd MDI child */
2084     { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
2085     { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
2086     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|0x8000 },
2087     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2088
2089     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2090
2091     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2092     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2093
2094     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2095
2096     { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
2097      /* in MDI frame */
2098     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2099     { WM_NCCALCSIZE, sent|wparam, 1 },
2100     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2101     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2102     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2103
2104     /* bring the 1st MDI child to top */
2105     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2106     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2107     { HCBT_SETFOCUS, hook },
2108     { WM_KILLFOCUS, sent|defwinproc },
2109     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
2110     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2111     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2112     { WM_SETFOCUS, sent }, /* in MDI client */
2113     { HCBT_SETFOCUS, hook },
2114     { WM_KILLFOCUS, sent }, /* in MDI client */
2115     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2116     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2117     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2118     { WM_SETFOCUS, sent|defwinproc },
2119     { WM_MDIACTIVATE, sent|defwinproc },
2120     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2121
2122     /* apparently ShowWindow(SW_SHOW) on an MDI client */
2123     { WM_SHOWWINDOW, sent|wparam, 1 },
2124     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2125     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2126     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2127     { WM_MDIREFRESHMENU, sent },
2128
2129     { HCBT_DESTROYWND, hook },
2130     /* Win2k sends wparam set to
2131      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2132      * while Win9x doesn't bother to set child window id according to
2133      * CLIENTCREATESTRUCT.idFirstChild
2134      */
2135     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2136     { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
2137     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2138     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2139     { WM_ERASEBKGND, sent|parent|optional },
2140     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2141
2142     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2143     { WM_DESTROY, sent|defwinproc },
2144     { WM_NCDESTROY, sent|defwinproc },
2145     { 0 }
2146 };
2147 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
2148 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
2149     { WM_MDIDESTROY, sent }, /* in MDI client */
2150     { WM_SHOWWINDOW, sent|wparam, 0 },
2151     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2152     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2153     { WM_ERASEBKGND, sent|parent|optional },
2154     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2155
2156     { HCBT_SETFOCUS, hook },
2157     { WM_KILLFOCUS, sent },
2158     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2159     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2160     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2161     { WM_SETFOCUS, sent }, /* in MDI client */
2162     { HCBT_SETFOCUS, hook },
2163     { WM_KILLFOCUS, sent }, /* in MDI client */
2164     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2165     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2166     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2167     { WM_SETFOCUS, sent },
2168
2169      /* in MDI child */
2170     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2171     { WM_NCCALCSIZE, sent|wparam, 1 },
2172     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2173     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2174
2175      /* in MDI frame */
2176     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2177     { WM_NCCALCSIZE, sent|wparam, 1 },
2178     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2179     { WM_MOVE, sent|defwinproc },
2180     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2181
2182      /* in MDI client */
2183     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2184     { WM_NCCALCSIZE, sent|wparam, 1 },
2185     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2186     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2187
2188      /* in MDI child */
2189     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2190     { WM_NCCALCSIZE, sent|wparam, 1 },
2191     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2192     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2193
2194      /* in MDI child */
2195     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2196     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2197     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2198     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2199
2200      /* in MDI frame */
2201     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2202     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2203     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2204     { WM_MOVE, sent|defwinproc },
2205     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2206
2207      /* in MDI client */
2208     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2209     { WM_NCCALCSIZE, sent|wparam, 1 },
2210     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2211     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2212
2213      /* in MDI child */
2214     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
2215     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2216     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2217     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2218     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2219     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2220
2221     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
2222
2223     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2224     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2225     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2226     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2227     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2228
2229      /* in MDI frame */
2230     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2231     { WM_NCCALCSIZE, sent|wparam, 1 },
2232     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2233     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2234
2235     { WM_NCACTIVATE, sent|wparam, 0 },
2236     { WM_MDIACTIVATE, sent },
2237
2238     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2239     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|0x8000 },
2240     { WM_NCCALCSIZE, sent|wparam, 1 },
2241
2242     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2243
2244     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2245     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|0x8000 },
2246     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2247
2248      /* in MDI child */
2249     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2250     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2251     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2252     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2253
2254      /* in MDI frame */
2255     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2256     { WM_NCCALCSIZE, sent|wparam, 1 },
2257     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2258     { WM_MOVE, sent|defwinproc },
2259     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2260
2261      /* in MDI client */
2262     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2263     { WM_NCCALCSIZE, sent|wparam, 1 },
2264     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2265     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2266     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2267     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2268     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2269     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2270     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2271
2272     { HCBT_SETFOCUS, hook },
2273     { WM_KILLFOCUS, sent },
2274     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2275     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2276     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2277     { WM_SETFOCUS, sent }, /* in MDI client */
2278
2279     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2280
2281     { HCBT_DESTROYWND, hook },
2282     /* Win2k sends wparam set to
2283      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2284      * while Win9x doesn't bother to set child window id according to
2285      * CLIENTCREATESTRUCT.idFirstChild
2286      */
2287     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2288
2289     { WM_SHOWWINDOW, sent|wparam, 0 },
2290     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2291     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2292     { WM_ERASEBKGND, sent|parent|optional },
2293     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2294
2295     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2296     { WM_DESTROY, sent },
2297     { WM_NCDESTROY, sent },
2298     { 0 }
2299 };
2300 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
2301 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
2302     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2303     { WM_GETMINMAXINFO, sent },
2304     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
2305     { WM_NCCALCSIZE, sent|wparam, 1 },
2306     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2307     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2308
2309     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2310     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2311     { HCBT_SETFOCUS, hook },
2312     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2313     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2314     { WM_SETFOCUS, sent }, /* in MDI client */
2315     { HCBT_SETFOCUS, hook },
2316     { WM_KILLFOCUS, sent }, /* in MDI client */
2317     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2318     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2319     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2320     { WM_SETFOCUS, sent|defwinproc },
2321     { WM_MDIACTIVATE, sent|defwinproc },
2322     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2323     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2324      /* in MDI frame */
2325     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2326     { WM_NCCALCSIZE, sent|wparam, 1 },
2327     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2328     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2329     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2330     { 0 }
2331 };
2332 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
2333 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
2334     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2335     { WM_GETMINMAXINFO, sent },
2336     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
2337     { WM_GETMINMAXINFO, sent|defwinproc },
2338     { WM_NCCALCSIZE, sent|wparam, 1 },
2339     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2340     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2341
2342     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2343     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2344     { HCBT_SETFOCUS, hook },
2345     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2346     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2347     { WM_SETFOCUS, sent }, /* in MDI client */
2348     { HCBT_SETFOCUS, hook },
2349     { WM_KILLFOCUS, sent }, /* in MDI client */
2350     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2351     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2352     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2353     { WM_SETFOCUS, sent|defwinproc },
2354     { WM_MDIACTIVATE, sent|defwinproc },
2355     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2356     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2357     { 0 }
2358 };
2359 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
2360 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
2361     { WM_MDIMAXIMIZE, sent }, /* in MDI client */
2362     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2363     { WM_GETMINMAXINFO, sent },
2364     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
2365     { WM_GETMINMAXINFO, sent|defwinproc },
2366     { WM_NCCALCSIZE, sent|wparam, 1 },
2367     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
2368     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2369     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|0x8000 },
2370     { WM_MOVE, sent|defwinproc },
2371     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2372
2373     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2374     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2375     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2376     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
2377     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2378     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
2379      /* in MDI frame */
2380     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2381     { WM_NCCALCSIZE, sent|wparam, 1 },
2382     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2383     { WM_MOVE, sent|defwinproc },
2384     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2385     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
2386      /* in MDI client */
2387     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2388     { WM_NCCALCSIZE, sent|wparam, 1 },
2389     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2390     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2391      /* in MDI child */
2392     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
2393     { WM_GETMINMAXINFO, sent|defwinproc },
2394     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2395     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2396     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2397     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
2398     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
2399     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2400     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2401     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
2402      /* in MDI frame */
2403     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
2404     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
2405     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
2406     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2407     { 0 }
2408 };
2409 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
2410 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
2411     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2412     { WM_GETMINMAXINFO, sent },
2413     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
2414     { WM_NCCALCSIZE, sent|wparam, 1 },
2415     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2416     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2417     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2418      /* in MDI frame */
2419     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2420     { WM_NCCALCSIZE, sent|wparam, 1 },
2421     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2422     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2423     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2424     { 0 }
2425 };
2426 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
2427 static const struct message WmRestoreMDIchildVisibleSeq[] = {
2428     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
2429     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
2430     { WM_NCCALCSIZE, sent|wparam, 1 },
2431     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2432     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2433     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2434      /* in MDI frame */
2435     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2436     { WM_NCCALCSIZE, sent|wparam, 1 },
2437     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2438     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2439     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2440     { 0 }
2441 };
2442 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
2443 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
2444     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
2445     { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
2446     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
2447     { WM_NCCALCSIZE, sent|wparam, 1 },
2448     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2449     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_NOCLIENTSIZE|0x8000 },
2450     { WM_MOVE, sent|defwinproc },
2451     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2452     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2453     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2454     { HCBT_SETFOCUS, hook },
2455     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2456     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2457     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2458     { WM_SETFOCUS, sent },
2459     { 0 }
2460 };
2461 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
2462 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
2463     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
2464     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|0x8000 },
2465     { WM_NCCALCSIZE, sent|wparam, 1 },
2466     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOCLIENTSIZE|0x8000 },
2467     { WM_MOVE, sent|defwinproc },
2468     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
2469     { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
2470     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2471     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2472     /* FIXME: Wine creates an icon/title window while Windows doesn't */
2473     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */
2474     { 0 }
2475 };
2476 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
2477 static const struct message WmRestoreMDIchildInisibleSeq[] = {
2478     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
2479     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
2480     { WM_NCCALCSIZE, sent|wparam, 1 },
2481     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2482     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2483     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2484     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2485      /* in MDI frame */
2486     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2487     { WM_NCCALCSIZE, sent|wparam, 1 },
2488     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2489     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2490     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2491     { 0 }
2492 };
2493
2494 static HWND mdi_client;
2495 static WNDPROC old_mdi_client_proc;
2496
2497 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2498 {
2499     struct message msg;
2500
2501     /* do not log painting messages */
2502     if (message != WM_PAINT &&
2503         message != WM_NCPAINT &&
2504         message != WM_SYNCPAINT &&
2505         message != WM_ERASEBKGND &&
2506         message != WM_NCPAINT &&
2507         message != WM_NCHITTEST &&
2508         message != WM_GETTEXT &&
2509         message != WM_MDIGETACTIVE &&
2510         message != WM_GETICON &&
2511         message != WM_DEVICECHANGE)
2512     {
2513         trace("mdi client: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2514
2515         switch (message)
2516         {
2517             case WM_WINDOWPOSCHANGING:
2518             case WM_WINDOWPOSCHANGED:
2519             {
2520                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
2521
2522                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
2523                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
2524                       winpos->hwnd, winpos->hwndInsertAfter,
2525                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
2526                 dump_winpos_flags(winpos->flags);
2527
2528                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2529                  * in the high word for internal purposes
2530                  */
2531                 wParam = winpos->flags & 0xffff;
2532                 /* We are not interested in the flags that don't match under XP and Win9x */
2533                 wParam &= ~(SWP_NOZORDER);
2534                 break;
2535             }
2536         }
2537
2538         msg.message = message;
2539         msg.flags = sent|wparam|lparam;
2540         msg.wParam = wParam;
2541         msg.lParam = lParam;
2542         add_message(&msg);
2543     }
2544
2545     return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
2546 }
2547
2548 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2549 {
2550     static long defwndproc_counter = 0;
2551     LRESULT ret;
2552     struct message msg;
2553
2554     /* do not log painting messages */
2555     if (message != WM_PAINT &&
2556         message != WM_NCPAINT &&
2557         message != WM_SYNCPAINT &&
2558         message != WM_ERASEBKGND &&
2559         message != WM_NCPAINT &&
2560         message != WM_NCHITTEST &&
2561         message != WM_GETTEXT &&
2562         message != WM_GETICON &&
2563         message != WM_DEVICECHANGE)
2564     {
2565         trace("mdi child: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2566
2567         switch (message)
2568         {
2569             case WM_WINDOWPOSCHANGING:
2570             case WM_WINDOWPOSCHANGED:
2571             {
2572                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
2573
2574                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
2575                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
2576                       winpos->hwnd, winpos->hwndInsertAfter,
2577                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
2578                 dump_winpos_flags(winpos->flags);
2579
2580                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2581                  * in the high word for internal purposes
2582                  */
2583                 wParam = winpos->flags & 0xffff;
2584                 /* We are not interested in the flags that don't match under XP and Win9x */
2585                 wParam &= ~(SWP_NOZORDER);
2586                 break;
2587             }
2588
2589             case WM_MDIACTIVATE:
2590             {
2591                 HWND active, client = GetParent(hwnd);
2592
2593                 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
2594
2595                 if (hwnd == (HWND)lParam) /* if we are being activated */
2596                     ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
2597                 else
2598                     ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
2599                 break;
2600             }
2601         }
2602
2603         msg.message = message;
2604         msg.flags = sent|wparam|lparam;
2605         if (defwndproc_counter) msg.flags |= defwinproc;
2606         msg.wParam = wParam;
2607         msg.lParam = lParam;
2608         add_message(&msg);
2609     }
2610
2611     defwndproc_counter++;
2612     ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
2613     defwndproc_counter--;
2614
2615     return ret;
2616 }
2617
2618 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2619 {
2620     static long defwndproc_counter = 0;
2621     LRESULT ret;
2622     struct message msg;
2623
2624     /* do not log painting messages */
2625     if (message != WM_PAINT &&
2626         message != WM_NCPAINT &&
2627         message != WM_SYNCPAINT &&
2628         message != WM_ERASEBKGND &&
2629         message != WM_NCPAINT &&
2630         message != WM_NCHITTEST &&
2631         message != WM_GETTEXT &&
2632         message != WM_GETICON &&
2633         message != WM_DEVICECHANGE)
2634     {
2635         trace("mdi frame: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2636
2637         switch (message)
2638         {
2639             case WM_WINDOWPOSCHANGING:
2640             case WM_WINDOWPOSCHANGED:
2641             {
2642                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
2643
2644                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
2645                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
2646                       winpos->hwnd, winpos->hwndInsertAfter,
2647                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
2648                 dump_winpos_flags(winpos->flags);
2649
2650                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2651                  * in the high word for internal purposes
2652                  */
2653                 wParam = winpos->flags & 0xffff;
2654                 /* We are not interested in the flags that don't match under XP and Win9x */
2655                 wParam &= ~(SWP_NOZORDER);
2656                 break;
2657             }
2658         }
2659
2660         msg.message = message;
2661         msg.flags = sent|wparam|lparam;
2662         if (defwndproc_counter) msg.flags |= defwinproc;
2663         msg.wParam = wParam;
2664         msg.lParam = lParam;
2665         add_message(&msg);
2666     }
2667
2668     defwndproc_counter++;
2669     ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
2670     defwndproc_counter--;
2671
2672     return ret;
2673 }
2674
2675 static BOOL mdi_RegisterWindowClasses(void)
2676 {
2677     WNDCLASSA cls;
2678
2679     cls.style = 0;
2680     cls.lpfnWndProc = mdi_frame_wnd_proc;
2681     cls.cbClsExtra = 0;
2682     cls.cbWndExtra = 0;
2683     cls.hInstance = GetModuleHandleA(0);
2684     cls.hIcon = 0;
2685     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
2686     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
2687     cls.lpszMenuName = NULL;
2688     cls.lpszClassName = "MDI_frame_class";
2689     if (!RegisterClassA(&cls)) return FALSE;
2690
2691     cls.lpfnWndProc = mdi_child_wnd_proc;
2692     cls.lpszClassName = "MDI_child_class";
2693     if (!RegisterClassA(&cls)) return FALSE;
2694
2695     if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
2696     old_mdi_client_proc = cls.lpfnWndProc;
2697     cls.hInstance = GetModuleHandleA(0);
2698     cls.lpfnWndProc = mdi_client_hook_proc;
2699     cls.lpszClassName = "MDI_client_class";
2700     if (!RegisterClassA(&cls)) assert(0);
2701
2702     return TRUE;
2703 }
2704
2705 static void test_mdi_messages(void)
2706 {
2707     MDICREATESTRUCTA mdi_cs;
2708     CLIENTCREATESTRUCT client_cs;
2709     HWND mdi_frame, mdi_child, mdi_child2, active_child;
2710     BOOL zoomed;
2711     HMENU hMenu = CreateMenu();
2712
2713     assert(mdi_RegisterWindowClasses());
2714
2715     flush_sequence();
2716
2717     trace("creating MDI frame window\n");
2718     mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
2719                                 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
2720                                 WS_MAXIMIZEBOX | WS_VISIBLE,
2721                                 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
2722                                 GetDesktopWindow(), hMenu,
2723                                 GetModuleHandleA(0), NULL);
2724     assert(mdi_frame);
2725     ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
2726
2727     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2728     ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
2729
2730     trace("creating MDI client window\n");
2731     client_cs.hWindowMenu = 0;
2732     client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
2733     mdi_client = CreateWindowExA(0, "MDI_client_class",
2734                                  NULL,
2735                                  WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
2736                                  0, 0, 0, 0,
2737                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
2738     assert(mdi_client);
2739     ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
2740
2741     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2742     ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
2743
2744     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2745     ok(!active_child, "wrong active MDI child %p\n", active_child);
2746     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2747
2748     SetFocus(0);
2749     flush_sequence();
2750
2751     trace("creating invisible MDI child window\n");
2752     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
2753                                 WS_CHILD,
2754                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
2755                                 mdi_client, 0, GetModuleHandleA(0), NULL);
2756     assert(mdi_child);
2757
2758     flush_sequence();
2759     ShowWindow(mdi_child, SW_SHOWNORMAL);
2760     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
2761
2762     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
2763     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
2764
2765     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2766     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2767
2768     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2769     ok(!active_child, "wrong active MDI child %p\n", active_child);
2770     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2771
2772     ShowWindow(mdi_child, SW_HIDE);
2773     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
2774     flush_sequence();
2775
2776     ShowWindow(mdi_child, SW_SHOW);
2777     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
2778
2779     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
2780     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
2781
2782     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2783     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2784
2785     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2786     ok(!active_child, "wrong active MDI child %p\n", active_child);
2787     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2788
2789     DestroyWindow(mdi_child);
2790     flush_sequence();
2791
2792     trace("creating visible MDI child window\n");
2793     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
2794                                 WS_CHILD | WS_VISIBLE,
2795                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
2796                                 mdi_client, 0, GetModuleHandleA(0), NULL);
2797     assert(mdi_child);
2798     ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
2799
2800     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
2801     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
2802
2803     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2804     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
2805
2806     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2807     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
2808     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2809     flush_sequence();
2810
2811     DestroyWindow(mdi_child);
2812     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
2813
2814     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2815     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2816
2817     /* Win2k: MDI client still returns a just destroyed child as active
2818      * Win9x: MDI client returns 0
2819      */
2820     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2821     ok(active_child == mdi_child || /* win2k */
2822        !active_child, /* win9x */
2823        "wrong active MDI child %p\n", active_child);
2824     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2825
2826     flush_sequence();
2827
2828     trace("creating invisible MDI child window\n");
2829     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
2830                                 WS_CHILD,
2831                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
2832                                 mdi_client, 0, GetModuleHandleA(0), NULL);
2833     assert(mdi_child2);
2834     ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
2835
2836     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
2837     ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
2838
2839     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2840     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2841
2842     /* Win2k: MDI client still returns a just destroyed child as active
2843      * Win9x: MDI client returns mdi_child2
2844      */
2845     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2846     ok(active_child == mdi_child || /* win2k */
2847        active_child == mdi_child2, /* win9x */
2848        "wrong active MDI child %p\n", active_child);
2849     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2850     flush_sequence();
2851
2852     ShowWindow(mdi_child2, SW_MAXIMIZE);
2853     ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
2854
2855     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
2856     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
2857
2858     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2859     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
2860     ok(zoomed, "wrong zoomed state %d\n", zoomed);
2861     flush_sequence();
2862
2863     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2864     ok(GetFocus() == mdi_child2 || /* win2k */
2865        GetFocus() == 0, /* win9x */
2866        "wrong focus window %p\n", GetFocus());
2867
2868     SetFocus(0);
2869     flush_sequence();
2870
2871     ShowWindow(mdi_child2, SW_HIDE);
2872     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
2873
2874     ShowWindow(mdi_child2, SW_RESTORE);
2875     ok_sequence(WmRestoreMDIchildInisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
2876     flush_sequence();
2877
2878     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
2879     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
2880
2881     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2882     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
2883     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2884     flush_sequence();
2885
2886     SetFocus(0);
2887     flush_sequence();
2888
2889     ShowWindow(mdi_child2, SW_HIDE);
2890     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
2891
2892     ShowWindow(mdi_child2, SW_SHOW);
2893     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
2894
2895     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2896     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2897
2898     ShowWindow(mdi_child2, SW_MAXIMIZE);
2899     ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
2900
2901     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2902     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2903
2904     ShowWindow(mdi_child2, SW_RESTORE);
2905     ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
2906
2907     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2908     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2909
2910     ShowWindow(mdi_child2, SW_MINIMIZE);
2911     ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", TRUE);
2912
2913     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2914     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2915
2916     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2917     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
2918     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2919     flush_sequence();
2920
2921     ShowWindow(mdi_child2, SW_RESTORE);
2922     ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", TRUE);
2923
2924     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2925     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
2926
2927     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2928     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
2929     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2930     flush_sequence();
2931
2932     SetFocus(0);
2933     flush_sequence();
2934
2935     ShowWindow(mdi_child2, SW_HIDE);
2936     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
2937
2938     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2939     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2940
2941     DestroyWindow(mdi_child2);
2942     ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
2943
2944     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2945     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2946
2947     /* test for maximized MDI children */
2948     trace("creating maximized visible MDI child window 1\n");
2949     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
2950                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
2951                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
2952                                 mdi_client, 0, GetModuleHandleA(0), NULL);
2953     assert(mdi_child);
2954     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
2955     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
2956
2957     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2958     ok(GetFocus() == mdi_child || /* win2k */
2959        GetFocus() == 0, /* win9x */
2960        "wrong focus window %p\n", GetFocus());
2961
2962     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2963     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
2964     ok(zoomed, "wrong zoomed state %d\n", zoomed);
2965     flush_sequence();
2966
2967     trace("creating maximized visible MDI child window 2\n");
2968     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
2969                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
2970                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
2971                                 mdi_client, 0, GetModuleHandleA(0), NULL);
2972     assert(mdi_child2);
2973     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
2974     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
2975     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
2976
2977     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2978     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
2979
2980     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2981     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
2982     ok(zoomed, "wrong zoomed state %d\n", zoomed);
2983     flush_sequence();
2984
2985     trace("destroying maximized visible MDI child window 2\n");
2986     DestroyWindow(mdi_child2);
2987     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
2988
2989     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
2990
2991     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2992     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2993
2994     /* Win2k: MDI client still returns a just destroyed child as active
2995      * Win9x: MDI client returns 0
2996      */
2997     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2998     ok(active_child == mdi_child2 || /* win2k */
2999        !active_child, /* win9x */
3000        "wrong active MDI child %p\n", active_child);
3001     flush_sequence();
3002
3003     ShowWindow(mdi_child, SW_MAXIMIZE);
3004     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3005     flush_sequence();
3006
3007     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3008     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3009
3010     trace("re-creating maximized visible MDI child window 2\n");
3011     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3012                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3013                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3014                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3015     assert(mdi_child2);
3016     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3017     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3018     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3019
3020     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3021     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3022
3023     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3024     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3025     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3026     flush_sequence();
3027
3028     SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
3029     ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
3030     ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
3031
3032     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3033     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3034     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3035
3036     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3037     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3038     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3039     flush_sequence();
3040
3041     DestroyWindow(mdi_child);
3042     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3043
3044     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3045     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3046
3047     /* Win2k: MDI client still returns a just destroyed child as active
3048      * Win9x: MDI client returns 0
3049      */
3050     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3051     ok(active_child == mdi_child || /* win2k */
3052        !active_child, /* win9x */
3053        "wrong active MDI child %p\n", active_child);
3054     flush_sequence();
3055
3056     trace("creating maximized invisible MDI child window\n");
3057     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3058                                 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
3059                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3060                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3061     assert(mdi_child2);
3062     ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", TRUE);
3063     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3064     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
3065     ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
3066
3067     /* Win2k: MDI client still returns a just destroyed child as active
3068      * Win9x: MDI client returns 0
3069      */
3070     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3071     ok(active_child == mdi_child || /* win2k */
3072        !active_child, /* win9x */
3073        "wrong active MDI child %p\n", active_child);
3074     flush_sequence();
3075
3076     trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
3077     ShowWindow(mdi_child2, SW_MAXIMIZE);
3078     ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
3079     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3080     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3081     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3082
3083     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3084     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3085     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3086     flush_sequence();
3087
3088     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3089     flush_sequence();
3090
3091     /* end of test for maximized MDI children */
3092
3093     mdi_cs.szClass = "MDI_child_Class";
3094     mdi_cs.szTitle = "MDI child";
3095     mdi_cs.hOwner = GetModuleHandleA(0);
3096     mdi_cs.x = 0;
3097     mdi_cs.y = 0;
3098     mdi_cs.cx = CW_USEDEFAULT;
3099     mdi_cs.cy = CW_USEDEFAULT;
3100     mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
3101     mdi_cs.lParam = 0;
3102     mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
3103     ok(mdi_child != 0, "MDI child creation failed\n");
3104     ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
3105
3106     ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
3107
3108     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3109     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3110
3111     ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
3112     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3113     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3114
3115     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3116     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3117     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3118     flush_sequence();
3119
3120     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3121     ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
3122
3123     ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
3124     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3125     ok(!active_child, "wrong active MDI child %p\n", active_child);
3126
3127     SetFocus(0);
3128     flush_sequence();
3129
3130     DestroyWindow(mdi_client);
3131     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3132
3133     /* test maximization of MDI child with invisible parent */
3134     client_cs.hWindowMenu = 0;
3135     mdi_client = CreateWindow("MDI_client_class",
3136                                  NULL,
3137                                  WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
3138                                  0, 0, 660, 430,
3139                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3140     ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
3141
3142     ShowWindow(mdi_client, SW_HIDE);
3143     ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
3144
3145     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3146                                 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
3147                                 0, 0, 650, 440,
3148                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3149     ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
3150
3151     SendMessage(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
3152     ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
3153     zoomed = IsZoomed(mdi_child);
3154     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3155     
3156     ShowWindow(mdi_client, SW_SHOW);
3157     ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
3158
3159     DestroyWindow(mdi_child);
3160     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
3161
3162     DestroyWindow(mdi_client);
3163     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3164     /* end of test for maximization of MDI child with invisible parent */
3165     
3166     DestroyWindow(mdi_frame);
3167     ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
3168 }
3169 /************************* End of MDI test **********************************/
3170
3171 static void test_WM_SETREDRAW(HWND hwnd)
3172 {
3173     DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
3174
3175     flush_sequence();
3176
3177     SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3178     ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
3179
3180     ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
3181     ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
3182
3183     flush_sequence();
3184     SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3185     ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
3186
3187     ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
3188     ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
3189
3190     /* restore original WS_VISIBLE state */
3191     SetWindowLongA(hwnd, GWL_STYLE, style);
3192
3193     flush_sequence();
3194 }
3195
3196 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3197 {
3198     struct message msg;
3199
3200     trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
3201
3202     /* explicitly ignore WM_GETICON message */
3203     if (message == WM_GETICON) return 0;
3204
3205     switch (message)
3206     {
3207         /* ignore */
3208         case WM_MOUSEMOVE:
3209         case WM_SETCURSOR:
3210         case WM_DEVICECHANGE:
3211             return 0;
3212         case WM_NCHITTEST:
3213             return HTCLIENT;
3214
3215         case WM_WINDOWPOSCHANGING:
3216         case WM_WINDOWPOSCHANGED:
3217         {
3218             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
3219
3220             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
3221             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
3222                   winpos->hwnd, winpos->hwndInsertAfter,
3223                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
3224             dump_winpos_flags(winpos->flags);
3225
3226             /* Log only documented flags, win2k uses 0x1000 and 0x2000
3227              * in the high word for internal purposes
3228              */
3229             wParam = winpos->flags & 0xffff;
3230             /* We are not interested in the flags that don't match under XP and Win9x */
3231             wParam &= ~(SWP_NOZORDER);
3232             break;
3233         }
3234     }
3235
3236     msg.message = message;
3237     msg.flags = sent|wparam|lparam;
3238     msg.wParam = wParam;
3239     msg.lParam = lParam;
3240     add_message(&msg);
3241
3242     if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
3243     if (message == WM_TIMER) EndDialog( hwnd, 0 );
3244     return 0;
3245 }
3246
3247 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
3248 {
3249     DWORD style, exstyle;
3250     INT xmin, xmax;
3251     BOOL ret;
3252
3253     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
3254     style = GetWindowLongA(hwnd, GWL_STYLE);
3255     /* do not be confused by WS_DLGFRAME set */
3256     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
3257
3258     if (clear) ok(style & clear, "style %08x should be set\n", clear);
3259     if (set) ok(!(style & set), "style %08x should not be set\n", set);
3260
3261     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3262     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
3263     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
3264         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
3265     else
3266         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
3267
3268     style = GetWindowLongA(hwnd, GWL_STYLE);
3269     if (set) ok(style & set, "style %08x should be set\n", set);
3270     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
3271
3272     /* a subsequent call should do nothing */
3273     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3274     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
3275     ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3276
3277     xmin = 0xdeadbeef;
3278     xmax = 0xdeadbeef;
3279     trace("Ignore GetScrollRange error below if you are on Win9x\n");
3280     ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
3281     ok( ret, "GetScrollRange(%d) error %d\n", ctl, GetLastError());
3282     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3283     ok(xmin == min, "unexpected min scroll value %d\n", xmin);
3284     ok(xmax == max, "unexpected max scroll value %d\n", xmax);
3285 }
3286
3287 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
3288 {
3289     DWORD style, exstyle;
3290     SCROLLINFO si;
3291     BOOL ret;
3292
3293     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
3294     style = GetWindowLongA(hwnd, GWL_STYLE);
3295     /* do not be confused by WS_DLGFRAME set */
3296     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
3297
3298     if (clear) ok(style & clear, "style %08x should be set\n", clear);
3299     if (set) ok(!(style & set), "style %08x should not be set\n", set);
3300
3301     si.cbSize = sizeof(si);
3302     si.fMask = SIF_RANGE;
3303     si.nMin = min;
3304     si.nMax = max;
3305     SetScrollInfo(hwnd, ctl, &si, TRUE);
3306     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
3307         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
3308     else
3309         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
3310
3311     style = GetWindowLongA(hwnd, GWL_STYLE);
3312     if (set) ok(style & set, "style %08x should be set\n", set);
3313     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
3314
3315     /* a subsequent call should do nothing */
3316     SetScrollInfo(hwnd, ctl, &si, TRUE);
3317     if (style & WS_HSCROLL)
3318         ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3319     else if (style & WS_VSCROLL)
3320         ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3321     else
3322         ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3323
3324     si.fMask = SIF_PAGE;
3325     si.nPage = 5;
3326     SetScrollInfo(hwnd, ctl, &si, FALSE);
3327     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3328
3329     si.fMask = SIF_POS;
3330     si.nPos = max - 1;
3331     SetScrollInfo(hwnd, ctl, &si, FALSE);
3332     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3333
3334     si.fMask = SIF_RANGE;
3335     si.nMin = 0xdeadbeef;
3336     si.nMax = 0xdeadbeef;
3337     ret = GetScrollInfo(hwnd, ctl, &si);
3338     ok( ret, "GetScrollInfo error %d\n", GetLastError());
3339     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3340     ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
3341     ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
3342 }
3343
3344 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
3345 static void test_scroll_messages(HWND hwnd)
3346 {
3347     SCROLLINFO si;
3348     INT min, max;
3349     BOOL ret;
3350
3351     min = 0xdeadbeef;
3352     max = 0xdeadbeef;
3353     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
3354     ok( ret, "GetScrollRange error %d\n", GetLastError());
3355     if (sequence->message != WmGetScrollRangeSeq[0].message)
3356         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
3357     /* values of min and max are undefined */
3358     flush_sequence();
3359
3360     ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
3361     ok( ret, "SetScrollRange error %d\n", GetLastError());
3362     if (sequence->message != WmSetScrollRangeSeq[0].message)
3363         trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
3364     flush_sequence();
3365
3366     min = 0xdeadbeef;
3367     max = 0xdeadbeef;
3368     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
3369     ok( ret, "GetScrollRange error %d\n", GetLastError());
3370     if (sequence->message != WmGetScrollRangeSeq[0].message)
3371         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
3372     /* values of min and max are undefined */
3373     flush_sequence();
3374
3375     si.cbSize = sizeof(si);
3376     si.fMask = SIF_RANGE;
3377     si.nMin = 20;
3378     si.nMax = 160;
3379     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
3380     if (sequence->message != WmSetScrollRangeSeq[0].message)
3381         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3382     flush_sequence();
3383
3384     si.fMask = SIF_PAGE;
3385     si.nPage = 10;
3386     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
3387     if (sequence->message != WmSetScrollRangeSeq[0].message)
3388         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3389     flush_sequence();
3390
3391     si.fMask = SIF_POS;
3392     si.nPos = 20;
3393     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
3394     if (sequence->message != WmSetScrollRangeSeq[0].message)
3395         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3396     flush_sequence();
3397
3398     si.fMask = SIF_RANGE;
3399     si.nMin = 0xdeadbeef;
3400     si.nMax = 0xdeadbeef;
3401     ret = GetScrollInfo(hwnd, SB_CTL, &si);
3402     ok( ret, "GetScrollInfo error %d\n", GetLastError());
3403     if (sequence->message != WmGetScrollInfoSeq[0].message)
3404         trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3405     /* values of min and max are undefined */
3406     flush_sequence();
3407
3408     /* set WS_HSCROLL */
3409     test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
3410     /* clear WS_HSCROLL */
3411     test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
3412
3413     /* set WS_HSCROLL */
3414     test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
3415     /* clear WS_HSCROLL */
3416     test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
3417
3418     /* set WS_VSCROLL */
3419     test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
3420     /* clear WS_VSCROLL */
3421     test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
3422
3423     /* set WS_VSCROLL */
3424     test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
3425     /* clear WS_VSCROLL */
3426     test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
3427 }
3428
3429 static void test_showwindow(void)
3430 {
3431     HWND hwnd, hchild;
3432     RECT rc;
3433
3434     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
3435                            100, 100, 200, 200, 0, 0, 0, NULL);
3436     ok (hwnd != 0, "Failed to create overlapped window\n");
3437     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
3438                              0, 0, 10, 10, hwnd, 0, 0, NULL);
3439     ok (hchild != 0, "Failed to create child\n");
3440     flush_sequence();
3441
3442     /* ShowWindow( SW_SHOWNA) for invisible top level window */
3443     trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
3444     ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
3445     ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", TRUE);
3446     trace("done\n");
3447
3448     /* ShowWindow( SW_SHOWNA) for now visible top level window */
3449     trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
3450     ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
3451     ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
3452     trace("done\n");
3453     /* back to invisible */
3454     ShowWindow(hchild, SW_HIDE);
3455     ShowWindow(hwnd, SW_HIDE);
3456     flush_sequence();
3457     /* ShowWindow(SW_SHOWNA) with child and parent invisible */ 
3458     trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
3459     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
3460     ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
3461     trace("done\n");
3462     /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */ 
3463     ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
3464     flush_sequence();
3465     trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
3466     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
3467     ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
3468     trace("done\n");
3469     /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
3470     ShowWindow( hwnd, SW_SHOW);
3471     flush_sequence();
3472     trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
3473     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
3474     ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
3475     trace("done\n");
3476
3477     /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
3478     ShowWindow( hchild, SW_HIDE);
3479     flush_sequence();
3480     trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
3481     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
3482     ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
3483     trace("done\n");
3484
3485     SetCapture(hchild);
3486     ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
3487     DestroyWindow(hchild);
3488     ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
3489
3490     DestroyWindow(hwnd);
3491     flush_sequence();
3492
3493     /* Popup windows */
3494     /* Test 1:
3495      * 1. Create invisible maximized popup window.
3496      * 2. Move and resize it.
3497      * 3. Show it maximized.
3498      */
3499     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
3500     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
3501                            100, 100, 200, 200, 0, 0, 0, NULL);
3502     ok (hwnd != 0, "Failed to create popup window\n");
3503     ok(IsZoomed(hwnd), "window should be maximized\n");
3504     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
3505     trace("done\n");
3506
3507     GetWindowRect(hwnd, &rc);
3508     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
3509         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
3510         "Invalid maximized size before ShowWindow (%d,%d)-(%d,%d)\n",
3511         rc.left, rc.top, rc.right, rc.bottom);
3512     /* Reset window's size & position */
3513     SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
3514     ok(IsZoomed(hwnd), "window should be maximized\n");
3515     flush_sequence();
3516
3517     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
3518     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
3519     ok(IsZoomed(hwnd), "window should be maximized\n");
3520     ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
3521     trace("done\n");
3522
3523     GetWindowRect(hwnd, &rc);
3524     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
3525         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
3526         "Invalid maximized size after ShowWindow (%d,%d)-(%d,%d)\n",
3527         rc.left, rc.top, rc.right, rc.bottom);
3528     DestroyWindow(hwnd);
3529     flush_sequence();
3530
3531     /* Test 2:
3532      * 1. Create invisible maximized popup window.
3533      * 2. Show it maximized.
3534      */
3535     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
3536     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
3537                            100, 100, 200, 200, 0, 0, 0, NULL);
3538     ok (hwnd != 0, "Failed to create popup window\n");
3539     ok(IsZoomed(hwnd), "window should be maximized\n");
3540     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
3541     trace("done\n");
3542
3543     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
3544     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
3545     ok(IsZoomed(hwnd), "window should be maximized\n");
3546     ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
3547     trace("done\n");
3548     DestroyWindow(hwnd);
3549     flush_sequence();
3550
3551     /* Test 3:
3552      * 1. Create visible maximized popup window.
3553      */
3554     trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
3555     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
3556                            100, 100, 200, 200, 0, 0, 0, NULL);
3557     ok (hwnd != 0, "Failed to create popup window\n");
3558     ok(IsZoomed(hwnd), "window should be maximized\n");
3559     ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
3560     trace("done\n");
3561     DestroyWindow(hwnd);
3562     flush_sequence();
3563
3564     /* Test 4:
3565      * 1. Create visible popup window.
3566      * 2. Maximize it.
3567      */
3568     trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
3569     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
3570                            100, 100, 200, 200, 0, 0, 0, NULL);
3571     ok (hwnd != 0, "Failed to create popup window\n");
3572     ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
3573     ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", TRUE);
3574     trace("done\n");
3575
3576     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
3577     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
3578     ok(IsZoomed(hwnd), "window should be maximized\n");
3579     ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
3580     trace("done\n");
3581     DestroyWindow(hwnd);
3582     flush_sequence();
3583 }
3584
3585 static void test_sys_menu(void)
3586 {
3587     HWND hwnd;
3588     HMENU hmenu;
3589     UINT state;
3590
3591     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
3592                            100, 100, 200, 200, 0, 0, 0, NULL);
3593     ok (hwnd != 0, "Failed to create overlapped window\n");
3594
3595     flush_sequence();
3596
3597     /* test existing window without CS_NOCLOSE style */
3598     hmenu = GetSystemMenu(hwnd, FALSE);
3599     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
3600
3601     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
3602     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
3603     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
3604
3605     EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
3606     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
3607
3608     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
3609     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
3610     ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
3611
3612     EnableMenuItem(hmenu, SC_CLOSE, 0);
3613     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
3614
3615     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
3616     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
3617     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
3618
3619     /* test whether removing WS_SYSMENU destroys a system menu */
3620     SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
3621     SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
3622     flush_sequence();
3623     hmenu = GetSystemMenu(hwnd, FALSE);
3624     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
3625
3626     DestroyWindow(hwnd);
3627
3628     /* test new window with CS_NOCLOSE style */
3629     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
3630                            100, 100, 200, 200, 0, 0, 0, NULL);
3631     ok (hwnd != 0, "Failed to create overlapped window\n");
3632
3633     hmenu = GetSystemMenu(hwnd, FALSE);
3634     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
3635
3636     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
3637     ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
3638
3639     DestroyWindow(hwnd);
3640
3641     /* test new window without WS_SYSMENU style */
3642     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
3643                            100, 100, 200, 200, 0, 0, 0, NULL);
3644     ok(hwnd != 0, "Failed to create overlapped window\n");
3645
3646     hmenu = GetSystemMenu(hwnd, FALSE);
3647     ok(!hmenu, "GetSystemMenu error %d\n", GetLastError());
3648
3649     DestroyWindow(hwnd);
3650 }
3651
3652 /* For shown WS_OVERLAPPEDWINDOW */
3653 static const struct message WmSetIcon_1[] = {
3654     { WM_SETICON, sent },
3655     { 0x00AE, sent|defwinproc|optional }, /* XP */
3656     { WM_GETTEXT, sent|defwinproc|optional },
3657     { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
3658     { 0 }
3659 };
3660
3661 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
3662 static const struct message WmSetIcon_2[] = {
3663     { WM_SETICON, sent },
3664     { 0 }
3665 };
3666
3667 static void test_MsgWaitForMultipleObjects(HWND hwnd)
3668 {
3669     DWORD ret;
3670     MSG msg;
3671
3672     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
3673     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
3674
3675     PostMessageA(hwnd, WM_USER, 0, 0);
3676
3677     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
3678     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
3679
3680     ok(PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
3681     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
3682
3683     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
3684     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
3685
3686     PostMessageA(hwnd, WM_USER, 0, 0);
3687
3688     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
3689     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
3690
3691     ok(PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
3692     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
3693
3694     /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
3695     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
3696     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
3697
3698     PostMessageA(hwnd, WM_USER, 0, 0);
3699
3700     /* new incoming message causes it to become signaled again */
3701     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
3702     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
3703
3704     ok(PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
3705     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
3706     ok(PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
3707     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
3708 }
3709
3710 /* test if we receive the right sequence of messages */
3711 static void test_messages(void)
3712 {
3713     HWND hwnd, hparent, hchild;
3714     HWND hchild2, hbutton;
3715     HMENU hmenu;
3716     MSG msg;
3717
3718     flush_sequence();
3719
3720     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
3721                            100, 100, 200, 200, 0, 0, 0, NULL);
3722     ok (hwnd != 0, "Failed to create overlapped window\n");
3723     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
3724
3725     /* test ShowWindow(SW_HIDE) on a newly created invisible window */
3726     ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
3727     ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
3728
3729     /* test WM_SETREDRAW on a not visible top level window */
3730     test_WM_SETREDRAW(hwnd);
3731
3732     SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
3733     ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
3734     ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
3735
3736     ok(GetActiveWindow() == hwnd, "window should be active\n");
3737     ok(GetFocus() == hwnd, "window should have input focus\n");
3738     ShowWindow(hwnd, SW_HIDE);
3739     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", TRUE);
3740
3741     ShowWindow(hwnd, SW_SHOW);
3742     ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
3743
3744     ShowWindow(hwnd, SW_HIDE);
3745     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
3746
3747     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
3748     ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
3749
3750     ShowWindow(hwnd, SW_RESTORE);
3751     /* FIXME: add ok_sequence() here */
3752     flush_sequence();
3753
3754     ShowWindow(hwnd, SW_MINIMIZE);
3755     ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE);
3756     flush_sequence();
3757
3758     ShowWindow(hwnd, SW_RESTORE);
3759     /* FIXME: add ok_sequence() here */
3760     flush_sequence();
3761
3762     ShowWindow(hwnd, SW_SHOW);
3763     ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
3764
3765     ok(GetActiveWindow() == hwnd, "window should be active\n");
3766     ok(GetFocus() == hwnd, "window should have input focus\n");
3767     SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
3768     ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
3769     ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
3770     ok(GetActiveWindow() == hwnd, "window should still be active\n");
3771
3772     /* test WM_SETREDRAW on a visible top level window */
3773     ShowWindow(hwnd, SW_SHOW);
3774     test_WM_SETREDRAW(hwnd);
3775
3776     trace("testing scroll APIs on a visible top level window %p\n", hwnd);
3777     test_scroll_messages(hwnd);
3778
3779     /* test resizing and moving */
3780     SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
3781     ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
3782     flush_events();
3783     flush_sequence();
3784     SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
3785     ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
3786     flush_events();
3787     flush_sequence();
3788     SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER );
3789     ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
3790     flush_events();
3791     flush_sequence();
3792
3793     /* popups don't get WM_GETMINMAXINFO */
3794     SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
3795     SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
3796     flush_sequence();
3797     SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
3798     ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
3799
3800     DestroyWindow(hwnd);
3801     ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
3802
3803     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
3804                               100, 100, 200, 200, 0, 0, 0, NULL);
3805     ok (hparent != 0, "Failed to create parent window\n");
3806     flush_sequence();
3807
3808     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
3809                              0, 0, 10, 10, hparent, 0, 0, NULL);
3810     ok (hchild != 0, "Failed to create child window\n");
3811     ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
3812     DestroyWindow(hchild);
3813     flush_sequence();
3814
3815     /* visible child window with a caption */
3816     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
3817                              WS_CHILD | WS_VISIBLE | WS_CAPTION,
3818                              0, 0, 10, 10, hparent, 0, 0, NULL);
3819     ok (hchild != 0, "Failed to create child window\n");
3820     ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
3821
3822     trace("testing scroll APIs on a visible child window %p\n", hchild);
3823     test_scroll_messages(hchild);
3824
3825     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
3826     ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
3827
3828     DestroyWindow(hchild);
3829     flush_sequence();
3830
3831     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
3832                              0, 0, 10, 10, hparent, 0, 0, NULL);
3833     ok (hchild != 0, "Failed to create child window\n");
3834     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
3835     
3836     hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
3837                                100, 100, 50, 50, hparent, 0, 0, NULL);
3838     ok (hchild2 != 0, "Failed to create child2 window\n");
3839     flush_sequence();
3840
3841     hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
3842                               0, 100, 50, 50, hchild, 0, 0, NULL);
3843     ok (hbutton != 0, "Failed to create button window\n");
3844
3845     /* test WM_SETREDRAW on a not visible child window */
3846     test_WM_SETREDRAW(hchild);
3847
3848     ShowWindow(hchild, SW_SHOW);
3849     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
3850
3851     ShowWindow(hchild, SW_HIDE);
3852     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
3853
3854     ShowWindow(hchild, SW_SHOW);
3855     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
3856
3857     /* test WM_SETREDRAW on a visible child window */
3858     test_WM_SETREDRAW(hchild);
3859
3860     MoveWindow(hchild, 10, 10, 20, 20, TRUE);
3861     ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
3862
3863     ShowWindow(hchild, SW_HIDE);
3864     flush_sequence();
3865     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
3866     ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
3867
3868     ShowWindow(hchild, SW_HIDE);
3869     flush_sequence();
3870     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
3871     ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
3872
3873     /* DestroyWindow sequence below expects that a child has focus */
3874     SetFocus(hchild);
3875     flush_sequence();
3876
3877     DestroyWindow(hchild);
3878     ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
3879     DestroyWindow(hchild2);
3880     DestroyWindow(hbutton);
3881
3882     flush_sequence();
3883     hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
3884                              0, 0, 100, 100, hparent, 0, 0, NULL);
3885     ok (hchild != 0, "Failed to create child popup window\n");
3886     ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
3887     DestroyWindow(hchild);
3888
3889     /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
3890     flush_sequence();
3891     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
3892                              0, 0, 100, 100, hparent, 0, 0, NULL);
3893     ok (hchild != 0, "Failed to create popup window\n");
3894     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
3895     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
3896     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
3897     flush_sequence();
3898     ShowWindow(hchild, SW_SHOW);
3899     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
3900     flush_sequence();
3901     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
3902     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
3903     flush_sequence();
3904     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
3905     ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
3906     DestroyWindow(hchild);
3907
3908     /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
3909      * changes nothing in message sequences.
3910      */
3911     flush_sequence();
3912     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
3913                              0, 0, 100, 100, hparent, 0, 0, NULL);
3914     ok (hchild != 0, "Failed to create popup window\n");
3915     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
3916     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
3917     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
3918     flush_sequence();
3919     ShowWindow(hchild, SW_SHOW);
3920     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
3921     flush_sequence();
3922     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
3923     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
3924     DestroyWindow(hchild);
3925
3926     flush_sequence();
3927     hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
3928                            0, 0, 100, 100, hparent, 0, 0, NULL);
3929     ok(hwnd != 0, "Failed to create custom dialog window\n");
3930     ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
3931
3932     /*
3933     trace("testing scroll APIs on a visible dialog %p\n", hwnd);
3934     test_scroll_messages(hwnd);
3935     */
3936
3937     flush_sequence();
3938
3939     test_def_id = 1;
3940     SendMessage(hwnd, WM_NULL, 0, 0);
3941
3942     flush_sequence();
3943     after_end_dialog = 1;
3944     EndDialog( hwnd, 0 );
3945     ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
3946
3947     DestroyWindow(hwnd);
3948     after_end_dialog = 0;
3949     test_def_id = 0;
3950
3951     hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP,
3952                            0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
3953     ok(hwnd != 0, "Failed to create custom dialog window\n");
3954     flush_sequence();
3955     trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
3956     ShowWindow(hwnd, SW_SHOW);
3957     ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
3958     DestroyWindow(hwnd);
3959
3960     flush_sequence();
3961     DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
3962     ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
3963
3964     DestroyWindow(hparent);
3965     flush_sequence();
3966
3967     /* Message sequence for SetMenu */
3968     ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a window without a menu\n");
3969     ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
3970
3971     hmenu = CreateMenu();
3972     ok (hmenu != 0, "Failed to create menu\n");
3973     ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
3974     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
3975                            100, 100, 200, 200, 0, hmenu, 0, NULL);
3976     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
3977     ok (SetMenu(hwnd, 0), "SetMenu\n");
3978     ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
3979     ok (SetMenu(hwnd, 0), "SetMenu\n");
3980     ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
3981     ShowWindow(hwnd, SW_SHOW);
3982     UpdateWindow( hwnd );
3983     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3984     flush_sequence();
3985     ok (SetMenu(hwnd, 0), "SetMenu\n");
3986     ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
3987     ok (SetMenu(hwnd, hmenu), "SetMenu\n");
3988     ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
3989
3990     UpdateWindow( hwnd );
3991     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3992     flush_sequence();
3993     ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
3994     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3995     ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
3996
3997     DestroyWindow(hwnd);
3998     flush_sequence();
3999
4000     /* Message sequence for EnableWindow */
4001     hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4002                               100, 100, 200, 200, 0, 0, 0, NULL);
4003     ok (hparent != 0, "Failed to create parent window\n");
4004     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
4005                              0, 0, 10, 10, hparent, 0, 0, NULL);
4006     ok (hchild != 0, "Failed to create child window\n");
4007
4008     SetFocus(hchild);
4009     flush_events();
4010     flush_sequence();
4011
4012     EnableWindow(hparent, FALSE);
4013     ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
4014
4015     EnableWindow(hparent, TRUE);
4016     ok_sequence(WmEnableWindowSeq_2, "EnableWindow(TRUE)", FALSE);
4017
4018     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4019     flush_sequence();
4020
4021     test_MsgWaitForMultipleObjects(hparent);
4022
4023     /* the following test causes an exception in user.exe under win9x */
4024     if (!PostMessageW( hparent, WM_USER, 0, 0 ))
4025     {
4026         DestroyWindow(hparent);
4027         flush_sequence();
4028         return;
4029     }
4030     PostMessageW( hparent, WM_USER+1, 0, 0 );
4031     /* PeekMessage(NULL) fails, but still removes the message */
4032     SetLastError(0xdeadbeef);
4033     ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
4034     ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
4035         GetLastError() == 0xdeadbeef, /* NT4 */
4036         "last error is %d\n", GetLastError() );
4037     ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
4038     ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
4039
4040     DestroyWindow(hchild);
4041     DestroyWindow(hparent);
4042     flush_sequence();
4043
4044     /* Message sequences for WM_SETICON */
4045     trace("testing WM_SETICON\n");
4046     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4047                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4048                            NULL, NULL, 0);
4049     ShowWindow(hwnd, SW_SHOW);
4050     UpdateWindow(hwnd);
4051     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4052     flush_sequence();
4053     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4054     ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
4055
4056     ShowWindow(hwnd, SW_HIDE);
4057     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4058     flush_sequence();
4059     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4060     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window with caption", FALSE);
4061     DestroyWindow(hwnd);
4062     flush_sequence();
4063
4064     hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
4065                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4066                            NULL, NULL, 0);
4067     ShowWindow(hwnd, SW_SHOW);
4068     UpdateWindow(hwnd);
4069     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4070     flush_sequence();
4071     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4072     ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
4073
4074     ShowWindow(hwnd, SW_HIDE);
4075     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4076     flush_sequence();
4077     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4078     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
4079     DestroyWindow(hwnd);
4080     flush_sequence();
4081 }
4082
4083 static void invisible_parent_tests(void)
4084 {
4085     HWND hparent, hchild;
4086
4087     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
4088                               100, 100, 200, 200, 0, 0, 0, NULL);
4089     ok (hparent != 0, "Failed to create parent window\n");
4090     flush_sequence();
4091
4092     /* test showing child with hidden parent */
4093
4094     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4095                              0, 0, 10, 10, hparent, 0, 0, NULL);
4096     ok (hchild != 0, "Failed to create child window\n");
4097     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4098
4099     ShowWindow( hchild, SW_MINIMIZE );
4100     ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4101     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4102     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4103
4104     /* repeat */
4105     flush_events();
4106     flush_sequence();
4107     ShowWindow( hchild, SW_MINIMIZE );
4108     ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4109
4110     DestroyWindow(hchild);
4111     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4112                              0, 0, 10, 10, hparent, 0, 0, NULL);
4113     flush_sequence();
4114
4115     ShowWindow( hchild, SW_MAXIMIZE );
4116     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
4117     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4118     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4119
4120     /* repeat */
4121     flush_events();
4122     flush_sequence();
4123     ShowWindow( hchild, SW_MAXIMIZE );
4124     ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
4125
4126     DestroyWindow(hchild);
4127     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4128                              0, 0, 10, 10, hparent, 0, 0, NULL);
4129     flush_sequence();
4130
4131     ShowWindow( hchild, SW_RESTORE );
4132     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
4133     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4134     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4135
4136     DestroyWindow(hchild);
4137     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4138                              0, 0, 10, 10, hparent, 0, 0, NULL);
4139     flush_sequence();
4140
4141     ShowWindow( hchild, SW_SHOWMINIMIZED );
4142     ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
4143     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4144     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4145
4146     /* repeat */
4147     flush_events();
4148     flush_sequence();
4149     ShowWindow( hchild, SW_SHOWMINIMIZED );
4150     ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
4151
4152     DestroyWindow(hchild);
4153     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4154                              0, 0, 10, 10, hparent, 0, 0, NULL);
4155     flush_sequence();
4156
4157     /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
4158     ShowWindow( hchild, SW_SHOWMAXIMIZED );
4159     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
4160     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4161     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4162
4163     DestroyWindow(hchild);
4164     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4165                              0, 0, 10, 10, hparent, 0, 0, NULL);
4166     flush_sequence();
4167
4168     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
4169     ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
4170     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4171     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4172
4173     /* repeat */
4174     flush_events();
4175     flush_sequence();
4176     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
4177     ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
4178
4179     DestroyWindow(hchild);
4180     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4181                              0, 0, 10, 10, hparent, 0, 0, NULL);
4182     flush_sequence();
4183
4184     /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
4185     ShowWindow( hchild, SW_FORCEMINIMIZE );
4186     ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
4187 todo_wine {
4188     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
4189 }
4190     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4191
4192     DestroyWindow(hchild);
4193     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4194                              0, 0, 10, 10, hparent, 0, 0, NULL);
4195     flush_sequence();
4196
4197     ShowWindow( hchild, SW_SHOWNA );
4198     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
4199     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4200     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4201
4202     /* repeat */
4203     flush_events();
4204     flush_sequence();
4205     ShowWindow( hchild, SW_SHOWNA );
4206     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
4207
4208     DestroyWindow(hchild);
4209     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4210                              0, 0, 10, 10, hparent, 0, 0, NULL);
4211     flush_sequence();
4212
4213     ShowWindow( hchild, SW_SHOW );
4214     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
4215     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4216     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4217
4218     /* repeat */
4219     flush_events();
4220     flush_sequence();
4221     ShowWindow( hchild, SW_SHOW );
4222     ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
4223
4224     ShowWindow( hchild, SW_HIDE );
4225     ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
4226     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
4227     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4228
4229     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4230     ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
4231     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4232     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4233
4234     SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4235     ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
4236     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
4237     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4238
4239     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4240     flush_sequence();
4241     DestroyWindow(hchild);
4242     ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
4243
4244     DestroyWindow(hparent);
4245     flush_sequence();
4246 }
4247
4248 /****************** button message test *************************/
4249 static const struct message WmSetFocusButtonSeq[] =
4250 {
4251     { HCBT_SETFOCUS, hook },
4252     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
4253     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4254     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4255     { WM_SETFOCUS, sent|wparam, 0 },
4256     { WM_CTLCOLORBTN, sent|defwinproc },
4257     { 0 }
4258 };
4259 static const struct message WmKillFocusButtonSeq[] =
4260 {
4261     { HCBT_SETFOCUS, hook },
4262     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4263     { WM_KILLFOCUS, sent|wparam, 0 },
4264     { WM_CTLCOLORBTN, sent|defwinproc },
4265     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
4266     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
4267     { 0 }
4268 };
4269 static const struct message WmSetFocusStaticSeq[] =
4270 {
4271     { HCBT_SETFOCUS, hook },
4272     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
4273     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4274     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4275     { WM_SETFOCUS, sent|wparam, 0 },
4276     { WM_CTLCOLORSTATIC, sent|defwinproc },
4277     { 0 }
4278 };
4279 static const struct message WmKillFocusStaticSeq[] =
4280 {
4281     { HCBT_SETFOCUS, hook },
4282     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4283     { WM_KILLFOCUS, sent|wparam, 0 },
4284     { WM_CTLCOLORSTATIC, sent|defwinproc },
4285     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
4286     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
4287     { 0 }
4288 };
4289 static const struct message WmLButtonDownSeq[] =
4290 {
4291     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
4292     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
4293     { HCBT_SETFOCUS, hook },
4294     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
4295     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4296     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4297     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
4298     { WM_CTLCOLORBTN, sent|defwinproc },
4299     { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
4300     { WM_CTLCOLORBTN, sent|defwinproc },
4301     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4302     { 0 }
4303 };
4304 static const struct message WmLButtonUpSeq[] =
4305 {
4306     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
4307     { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
4308     { WM_CTLCOLORBTN, sent|defwinproc },
4309     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4310     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
4311     { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
4312     { 0 }
4313 };
4314 static const struct message WmSetFontButtonSeq[] =
4315 {
4316     { WM_SETFONT, sent },
4317     { WM_PAINT, sent },
4318     { WM_ERASEBKGND, sent|defwinproc|optional },
4319     { WM_CTLCOLORBTN, sent|defwinproc },
4320     { 0 }
4321 };
4322
4323 static WNDPROC old_button_proc;
4324
4325 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4326 {
4327     static long defwndproc_counter = 0;
4328     LRESULT ret;
4329     struct message msg;
4330
4331     trace("button: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
4332
4333     /* explicitly ignore WM_GETICON message */
4334     if (message == WM_GETICON) return 0;
4335
4336     msg.message = message;
4337     msg.flags = sent|wparam|lparam;
4338     if (defwndproc_counter) msg.flags |= defwinproc;
4339     msg.wParam = wParam;
4340     msg.lParam = lParam;
4341     add_message(&msg);
4342
4343     if (message == BM_SETSTATE)
4344         ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
4345
4346     defwndproc_counter++;
4347     ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
4348     defwndproc_counter--;
4349
4350     return ret;
4351 }
4352
4353 static void subclass_button(void)
4354 {
4355     WNDCLASSA cls;
4356
4357     if (!GetClassInfoA(0, "button", &cls)) assert(0);
4358
4359     old_button_proc = cls.lpfnWndProc;
4360
4361     cls.hInstance = GetModuleHandle(0);
4362     cls.lpfnWndProc = button_hook_proc;
4363     cls.lpszClassName = "my_button_class";
4364     UnregisterClass(cls.lpszClassName, cls.hInstance);
4365     if (!RegisterClassA(&cls)) assert(0);
4366 }
4367
4368 static void test_button_messages(void)
4369 {
4370     static const struct
4371     {
4372         DWORD style;
4373         DWORD dlg_code;
4374         const struct message *setfocus;
4375         const struct message *killfocus;
4376     } button[] = {
4377         { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
4378           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
4379         { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
4380           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
4381         { BS_CHECKBOX, DLGC_BUTTON,
4382           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4383         { BS_AUTOCHECKBOX, DLGC_BUTTON,
4384           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4385         { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
4386           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4387         { BS_3STATE, DLGC_BUTTON,
4388           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4389         { BS_AUTO3STATE, DLGC_BUTTON,
4390           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4391         { BS_GROUPBOX, DLGC_STATIC,
4392           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4393         { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
4394           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
4395         { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
4396           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4397         { BS_OWNERDRAW, DLGC_BUTTON,
4398           WmSetFocusButtonSeq, WmKillFocusButtonSeq }
4399     };
4400     unsigned int i;
4401     HWND hwnd;
4402     DWORD dlg_code;
4403     HFONT zfont;
4404
4405     subclass_button();
4406
4407     for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
4408     {
4409         hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP,
4410                                0, 0, 50, 14, 0, 0, 0, NULL);
4411         ok(hwnd != 0, "Failed to create button window\n");
4412
4413         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
4414         ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
4415
4416         ShowWindow(hwnd, SW_SHOW);
4417         UpdateWindow(hwnd);
4418         SetFocus(0);
4419         flush_sequence();
4420
4421         trace("button style %08x\n", button[i].style);
4422         SetFocus(hwnd);
4423         ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
4424
4425         SetFocus(0);
4426         ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
4427
4428         DestroyWindow(hwnd);
4429     }
4430
4431     hwnd = CreateWindowExA(0, "my_button_class", "test", BS_PUSHBUTTON | WS_POPUP | WS_VISIBLE,
4432                            0, 0, 50, 14, 0, 0, 0, NULL);
4433     ok(hwnd != 0, "Failed to create button window\n");
4434
4435     SetFocus(0);
4436     flush_sequence();
4437
4438     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
4439     ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
4440
4441     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
4442     ok_sequence(WmLButtonUpSeq, "WM_LBUTTONUP on a button", FALSE);
4443
4444     flush_sequence();
4445     zfont = (HFONT)GetStockObject(SYSTEM_FONT);
4446     SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
4447     UpdateWindow(hwnd);
4448     ok_sequence(WmSetFontButtonSeq, "WM_SETFONT on a button", FALSE);
4449
4450     DestroyWindow(hwnd);
4451 }
4452
4453 /****************** static message test *************************/
4454 static const struct message WmSetFontStaticSeq[] =
4455 {
4456     { WM_SETFONT, sent },
4457     { WM_PAINT, sent|defwinproc },
4458     { WM_ERASEBKGND, sent|defwinproc|optional },
4459     { WM_CTLCOLORSTATIC, sent|defwinproc },
4460     { 0 }
4461 };
4462
4463 static WNDPROC old_static_proc;
4464
4465 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4466 {
4467     static long defwndproc_counter = 0;
4468     LRESULT ret;
4469     struct message msg;
4470
4471     trace("static: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
4472
4473     /* explicitly ignore WM_GETICON message */
4474     if (message == WM_GETICON) return 0;
4475
4476     msg.message = message;
4477     msg.flags = sent|wparam|lparam;
4478     if (defwndproc_counter) msg.flags |= defwinproc;
4479     msg.wParam = wParam;
4480     msg.lParam = lParam;
4481     add_message(&msg);
4482
4483
4484     defwndproc_counter++;
4485     ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
4486     defwndproc_counter--;
4487
4488     return ret;
4489 }
4490
4491 static void subclass_static(void)
4492 {
4493     WNDCLASSA cls;
4494
4495     if (!GetClassInfoA(0, "static", &cls)) assert(0);
4496
4497     old_static_proc = cls.lpfnWndProc;
4498
4499     cls.hInstance = GetModuleHandle(0);
4500     cls.lpfnWndProc = static_hook_proc;
4501     cls.lpszClassName = "my_static_class";
4502     UnregisterClass(cls.lpszClassName, cls.hInstance);
4503     if (!RegisterClassA(&cls)) assert(0);
4504 }
4505
4506 static void test_static_messages(void)
4507 {
4508     /* FIXME: make as comprehensive as the button message test */
4509     static const struct
4510     {
4511         DWORD style;
4512         DWORD dlg_code;
4513         const struct message *setfont;
4514     } static_ctrl[] = {
4515         { SS_LEFT, DLGC_STATIC,
4516           WmSetFontStaticSeq }
4517     };
4518     unsigned int i;
4519     HWND hwnd;
4520     DWORD dlg_code;
4521
4522     subclass_static();
4523
4524     for (i = 0; i < sizeof(static_ctrl)/sizeof(static_ctrl[0]); i++)
4525     {
4526         hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
4527                                0, 0, 50, 14, 0, 0, 0, NULL);
4528         ok(hwnd != 0, "Failed to create static window\n");
4529
4530         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
4531         ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
4532
4533         ShowWindow(hwnd, SW_SHOW);
4534         UpdateWindow(hwnd);
4535         SetFocus(0);
4536         flush_sequence();
4537
4538         trace("static style %08x\n", static_ctrl[i].style);
4539         SendMessage(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
4540         ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
4541
4542         DestroyWindow(hwnd);
4543     }
4544 }
4545
4546 /************* painting message test ********************/
4547
4548 void dump_region(HRGN hrgn)
4549 {
4550     DWORD i, size;
4551     RGNDATA *data = NULL;
4552     RECT *rect;
4553
4554     if (!hrgn)
4555     {
4556         printf( "null region\n" );
4557         return;
4558     }
4559     if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
4560     if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
4561     GetRegionData( hrgn, size, data );
4562     printf("%d rects:", data->rdh.nCount );
4563     for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
4564         printf( " (%d,%d)-(%d,%d)", rect->left, rect->top, rect->right, rect->bottom );
4565     printf("\n");
4566     HeapFree( GetProcessHeap(), 0, data );
4567 }
4568
4569 static void check_update_rgn( HWND hwnd, HRGN hrgn )
4570 {
4571     INT ret;
4572     RECT r1, r2;
4573     HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
4574     HRGN update = CreateRectRgn( 0, 0, 0, 0 );
4575
4576     ret = GetUpdateRgn( hwnd, update, FALSE );
4577     ok( ret != ERROR, "GetUpdateRgn failed\n" );
4578     if (ret == NULLREGION)
4579     {
4580         ok( !hrgn, "Update region shouldn't be empty\n" );
4581     }
4582     else
4583     {
4584         if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
4585         {
4586             ok( 0, "Regions are different\n" );
4587             if (winetest_debug > 0)
4588             {
4589                 printf( "Update region: " );
4590                 dump_region( update );
4591                 printf( "Wanted region: " );
4592                 dump_region( hrgn );
4593             }
4594         }
4595     }
4596     GetRgnBox( update, &r1 );
4597     GetUpdateRect( hwnd, &r2, FALSE );
4598     ok( r1.left == r2.left && r1.top == r2.top && r1.right == r2.right && r1.bottom == r2.bottom,
4599         "Rectangles are different: %d,%d-%d,%d / %d,%d-%d,%d\n",
4600         r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom );
4601
4602     DeleteObject( tmp );
4603     DeleteObject( update );
4604 }
4605
4606 static const struct message WmInvalidateRgn[] = {
4607     { WM_NCPAINT, sent },
4608     { WM_GETTEXT, sent|defwinproc|optional },
4609     { 0 }
4610 };
4611
4612 static const struct message WmGetUpdateRect[] = {
4613     { WM_NCPAINT, sent },
4614     { WM_GETTEXT, sent|defwinproc|optional },
4615     { WM_PAINT, sent },
4616     { 0 }
4617 };
4618
4619 static const struct message WmInvalidateFull[] = {
4620     { WM_NCPAINT, sent|wparam, 1 },
4621     { WM_GETTEXT, sent|defwinproc|optional },
4622     { 0 }
4623 };
4624
4625 static const struct message WmInvalidateErase[] = {
4626     { WM_NCPAINT, sent|wparam, 1 },
4627     { WM_GETTEXT, sent|defwinproc|optional },
4628     { WM_ERASEBKGND, sent },
4629     { 0 }
4630 };
4631
4632 static const struct message WmInvalidatePaint[] = {
4633     { WM_PAINT, sent },
4634     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
4635     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4636     { 0 }
4637 };
4638
4639 static const struct message WmInvalidateErasePaint[] = {
4640     { WM_PAINT, sent },
4641     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
4642     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4643     { WM_ERASEBKGND, sent|beginpaint },
4644     { 0 }
4645 };
4646
4647 static const struct message WmInvalidateErasePaint2[] = {
4648     { WM_PAINT, sent },
4649     { WM_NCPAINT, sent|beginpaint },
4650     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4651     { WM_ERASEBKGND, sent|beginpaint },
4652     { 0 }
4653 };
4654
4655 static const struct message WmErase[] = {
4656     { WM_ERASEBKGND, sent },
4657     { 0 }
4658 };
4659
4660 static const struct message WmPaint[] = {
4661     { WM_PAINT, sent },
4662     { 0 }
4663 };
4664
4665 static const struct message WmParentOnlyPaint[] = {
4666     { WM_PAINT, sent|parent },
4667     { 0 }
4668 };
4669
4670 static const struct message WmInvalidateParent[] = {
4671     { WM_NCPAINT, sent|parent },
4672     { WM_GETTEXT, sent|defwinproc|parent|optional },
4673     { WM_ERASEBKGND, sent|parent },
4674     { 0 }
4675 };
4676
4677 static const struct message WmInvalidateParentChild[] = {
4678     { WM_NCPAINT, sent|parent },
4679     { WM_GETTEXT, sent|defwinproc|parent|optional },
4680     { WM_ERASEBKGND, sent|parent },
4681     { WM_NCPAINT, sent },
4682     { WM_GETTEXT, sent|defwinproc|optional },
4683     { WM_ERASEBKGND, sent },
4684     { 0 }
4685 };
4686
4687 static const struct message WmInvalidateParentChild2[] = {
4688     { WM_ERASEBKGND, sent|parent },
4689     { WM_NCPAINT, sent },
4690     { WM_GETTEXT, sent|defwinproc|optional },
4691     { WM_ERASEBKGND, sent },
4692     { 0 }
4693 };
4694
4695 static const struct message WmParentPaint[] = {
4696     { WM_PAINT, sent|parent },
4697     { WM_PAINT, sent },
4698     { 0 }
4699 };
4700
4701 static const struct message WmParentPaintNc[] = {
4702     { WM_PAINT, sent|parent },
4703     { WM_PAINT, sent },
4704     { WM_NCPAINT, sent|beginpaint },
4705     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4706     { WM_ERASEBKGND, sent|beginpaint },
4707     { 0 }
4708 };
4709
4710 static const struct message WmChildPaintNc[] = {
4711     { WM_PAINT, sent },
4712     { WM_NCPAINT, sent|beginpaint },
4713     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4714     { WM_ERASEBKGND, sent|beginpaint },
4715     { 0 }
4716 };
4717
4718 static const struct message WmParentErasePaint[] = {
4719     { WM_PAINT, sent|parent },
4720     { WM_NCPAINT, sent|parent|beginpaint },
4721     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
4722     { WM_ERASEBKGND, sent|parent|beginpaint },
4723     { WM_PAINT, sent },
4724     { WM_NCPAINT, sent|beginpaint },
4725     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4726     { WM_ERASEBKGND, sent|beginpaint },
4727     { 0 }
4728 };
4729
4730 static const struct message WmParentOnlyNcPaint[] = {
4731     { WM_PAINT, sent|parent },
4732     { WM_NCPAINT, sent|parent|beginpaint },
4733     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
4734     { 0 }
4735 };
4736
4737 static const struct message WmSetParentStyle[] = {
4738     { WM_STYLECHANGING, sent|parent },
4739     { WM_STYLECHANGED, sent|parent },
4740     { 0 }
4741 };
4742
4743 static void test_paint_messages(void)
4744 {
4745     BOOL ret;
4746     RECT rect;
4747     POINT pt;
4748     MSG msg;
4749     HWND hparent, hchild;
4750     HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
4751     HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
4752     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4753                                 100, 100, 200, 200, 0, 0, 0, NULL);
4754     ok (hwnd != 0, "Failed to create overlapped window\n");
4755
4756     ShowWindow( hwnd, SW_SHOW );
4757     UpdateWindow( hwnd );
4758     flush_events();
4759     flush_sequence();
4760
4761     check_update_rgn( hwnd, 0 );
4762     SetRectRgn( hrgn, 10, 10, 20, 20 );
4763     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
4764     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
4765     check_update_rgn( hwnd, hrgn );
4766     SetRectRgn( hrgn2, 20, 20, 30, 30 );
4767     ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
4768     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
4769     CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
4770     check_update_rgn( hwnd, hrgn );
4771     /* validate everything */
4772     ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
4773     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
4774     check_update_rgn( hwnd, 0 );
4775
4776     /* test empty region */
4777     SetRectRgn( hrgn, 10, 10, 10, 15 );
4778     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
4779     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
4780     check_update_rgn( hwnd, 0 );
4781     /* test empty rect */
4782     SetRect( &rect, 10, 10, 10, 15 );
4783     ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
4784     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
4785     check_update_rgn( hwnd, 0 );
4786
4787     /* flush pending messages */
4788     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4789     flush_sequence();
4790
4791     GetClientRect( hwnd, &rect );
4792     SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
4793     /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
4794      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
4795      */
4796     trace("testing InvalidateRect(0, NULL, FALSE)\n");
4797     SetRectEmpty( &rect );
4798     ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) should fail\n");
4799     check_update_rgn( hwnd, hrgn );
4800     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
4801     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4802     ok_sequence( WmPaint, "Paint", FALSE );
4803     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
4804     check_update_rgn( hwnd, 0 );
4805
4806     /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
4807      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
4808      */
4809     trace("testing ValidateRect(0, NULL)\n");
4810     SetRectEmpty( &rect );
4811     ok(ValidateRect(0, &rect), "ValidateRect(0, &rc) should not fail\n");
4812     check_update_rgn( hwnd, hrgn );
4813     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
4814     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4815     ok_sequence( WmPaint, "Paint", FALSE );
4816     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
4817     check_update_rgn( hwnd, 0 );
4818
4819     trace("testing InvalidateRgn(0, NULL, FALSE)\n");
4820     SetLastError(0xdeadbeef);
4821     ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
4822     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error code %d\n", GetLastError());
4823     check_update_rgn( hwnd, 0 );
4824     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4825     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
4826
4827     trace("testing ValidateRgn(0, NULL)\n");
4828     SetLastError(0xdeadbeef);
4829     ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
4830     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error code %d\n", GetLastError());
4831     check_update_rgn( hwnd, 0 );
4832     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4833     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
4834
4835     /* now with frame */
4836     SetRectRgn( hrgn, -5, -5, 20, 20 );
4837
4838     /* flush pending messages */
4839     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4840
4841     flush_sequence();
4842     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
4843     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
4844
4845     SetRectRgn( hrgn, 0, 0, 20, 20 );  /* GetUpdateRgn clips to client area */
4846     check_update_rgn( hwnd, hrgn );
4847
4848     flush_sequence();
4849     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
4850     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
4851
4852     flush_sequence();
4853     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
4854     ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
4855
4856     GetClientRect( hwnd, &rect );
4857     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
4858     check_update_rgn( hwnd, hrgn );
4859
4860     flush_sequence();
4861     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
4862     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
4863
4864     flush_sequence();
4865     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
4866     ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
4867     check_update_rgn( hwnd, 0 );
4868
4869     flush_sequence();
4870     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
4871     ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
4872     check_update_rgn( hwnd, 0 );
4873
4874     flush_sequence();
4875     SetRectRgn( hrgn, 0, 0, 100, 100 );
4876     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
4877     SetRectRgn( hrgn, 0, 0, 50, 100 );
4878     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
4879     SetRectRgn( hrgn, 50, 0, 100, 100 );
4880     check_update_rgn( hwnd, hrgn );
4881     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
4882     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );  /* must not generate messages, everything is valid */
4883     check_update_rgn( hwnd, 0 );
4884
4885     flush_sequence();
4886     SetRectRgn( hrgn, 0, 0, 100, 100 );
4887     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
4888     SetRectRgn( hrgn, 0, 0, 100, 50 );
4889     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
4890     ok_sequence( WmErase, "Erase", FALSE );
4891     SetRectRgn( hrgn, 0, 50, 100, 100 );
4892     check_update_rgn( hwnd, hrgn );
4893
4894     flush_sequence();
4895     SetRectRgn( hrgn, 0, 0, 100, 100 );
4896     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
4897     SetRectRgn( hrgn, 0, 0, 50, 50 );
4898     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
4899     ok_sequence( WmPaint, "Paint", FALSE );
4900
4901     flush_sequence();
4902     SetRectRgn( hrgn, -4, -4, -2, -2 );
4903     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
4904     SetRectRgn( hrgn, -200, -200, -198, -198 );
4905     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
4906     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
4907
4908     flush_sequence();
4909     SetRectRgn( hrgn, -4, -4, -2, -2 );
4910     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
4911     SetRectRgn( hrgn, -4, -4, -3, -3 );
4912     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
4913     SetRectRgn( hrgn, 0, 0, 1, 1 );
4914     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
4915     ok_sequence( WmPaint, "Paint", FALSE );
4916
4917     flush_sequence();
4918     SetRectRgn( hrgn, -4, -4, -1, -1 );
4919     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
4920     RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
4921     /* make sure no WM_PAINT was generated */
4922     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4923     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
4924
4925     flush_sequence();
4926     SetRectRgn( hrgn, -4, -4, -1, -1 );
4927     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
4928     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
4929     {
4930         if (msg.hwnd == hwnd && msg.message == WM_PAINT)
4931         {
4932             /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
4933             INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
4934             ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
4935             ret = GetUpdateRect( hwnd, &rect, FALSE );
4936             ok( ret, "Invalid GetUpdateRect result %d\n", ret );
4937             /* this will send WM_NCPAINT and validate the non client area */
4938             ret = GetUpdateRect( hwnd, &rect, TRUE );
4939             ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
4940         }
4941         DispatchMessage( &msg );
4942     }
4943     ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
4944
4945     DestroyWindow( hwnd );
4946
4947     /* now test with a child window */
4948
4949     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
4950                               100, 100, 200, 200, 0, 0, 0, NULL);
4951     ok (hparent != 0, "Failed to create parent window\n");
4952
4953     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
4954                            10, 10, 100, 100, hparent, 0, 0, NULL);
4955     ok (hchild != 0, "Failed to create child window\n");
4956
4957     ShowWindow( hparent, SW_SHOW );
4958     UpdateWindow( hparent );
4959     UpdateWindow( hchild );
4960     flush_events();
4961     flush_sequence();
4962     log_all_parent_messages++;
4963
4964     SetRect( &rect, 0, 0, 50, 50 );
4965     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
4966     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
4967     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
4968
4969     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
4970     pt.x = pt.y = 0;
4971     MapWindowPoints( hchild, hparent, &pt, 1 );
4972     SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
4973     check_update_rgn( hchild, hrgn );
4974     SetRectRgn( hrgn, 0, 0, 50, 50 );
4975     check_update_rgn( hparent, hrgn );
4976     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
4977     ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
4978     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
4979     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
4980
4981     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4982     ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
4983
4984     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
4985     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
4986     ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
4987     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
4988     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
4989
4990     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
4991     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
4992     ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
4993
4994     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
4995     flush_sequence();
4996     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
4997     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
4998     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
4999
5000     /* flush all paint messages */
5001     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5002     flush_sequence();
5003
5004     /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
5005     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
5006     SetRectRgn( hrgn, 0, 0, 50, 50 );
5007     check_update_rgn( hparent, hrgn );
5008     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
5009     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5010     SetRectRgn( hrgn, 0, 0, 50, 50 );
5011     check_update_rgn( hparent, hrgn );
5012
5013     /* flush all paint messages */
5014     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5015     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
5016     flush_sequence();
5017
5018     /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
5019     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5020     SetRectRgn( hrgn, 0, 0, 50, 50 );
5021     check_update_rgn( hparent, hrgn );
5022     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
5023     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5024     SetRectRgn( hrgn2, 10, 10, 50, 50 );
5025     CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
5026     check_update_rgn( hparent, hrgn );
5027     /* flush all paint messages */
5028     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5029     flush_sequence();
5030
5031     /* same as above but parent gets completely validated */
5032     SetRect( &rect, 20, 20, 30, 30 );
5033     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5034     SetRectRgn( hrgn, 20, 20, 30, 30 );
5035     check_update_rgn( hparent, hrgn );
5036     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
5037     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5038     check_update_rgn( hparent, 0 );  /* no update region */
5039     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5040     ok_sequence( WmEmptySeq, "WmEmpty", FALSE );  /* and no paint messages */
5041
5042     /* make sure RDW_VALIDATE on child doesn't have the same effect */
5043     flush_sequence();
5044     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5045     SetRectRgn( hrgn, 20, 20, 30, 30 );
5046     check_update_rgn( hparent, hrgn );
5047     RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
5048     SetRectRgn( hrgn, 20, 20, 30, 30 );
5049     check_update_rgn( hparent, hrgn );
5050
5051     /* same as above but normal WM_PAINT doesn't validate parent */
5052     flush_sequence();
5053     SetRect( &rect, 20, 20, 30, 30 );
5054     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5055     SetRectRgn( hrgn, 20, 20, 30, 30 );
5056     check_update_rgn( hparent, hrgn );
5057     /* no WM_PAINT in child while parent still pending */
5058     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5059     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
5060     while (PeekMessage( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5061     ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
5062
5063     flush_sequence();
5064     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5065     /* no WM_PAINT in child while parent still pending */
5066     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5067     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
5068     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
5069     /* now that parent is valid child should get WM_PAINT */
5070     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5071     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5072     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5073     ok_sequence( WmEmptySeq, "No other message", FALSE );
5074
5075     /* same thing with WS_CLIPCHILDREN in parent */
5076     flush_sequence();
5077     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
5078     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
5079     /* changing style invalidates non client area, but we need to invalidate something else to see it */
5080     RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
5081     ok_sequence( WmEmptySeq, "No message", FALSE );
5082     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
5083     ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
5084
5085     flush_sequence();
5086     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
5087     SetRectRgn( hrgn, 20, 20, 30, 30 );
5088     check_update_rgn( hparent, hrgn );
5089     /* no WM_PAINT in child while parent still pending */
5090     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5091     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
5092     /* WM_PAINT in parent first */
5093     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5094     ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
5095
5096     /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
5097     flush_sequence();
5098     SetRect( &rect, 0, 0, 30, 30 );
5099     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
5100     SetRectRgn( hrgn, 0, 0, 30, 30 );
5101     check_update_rgn( hparent, hrgn );
5102     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5103     ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
5104
5105     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
5106     flush_sequence();
5107     SetRect( &rect, -10, 0, 30, 30 );
5108     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
5109     SetRect( &rect, 0, 0, 20, 20 );
5110     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
5111     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
5112     ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
5113
5114     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
5115     flush_sequence();
5116     SetRect( &rect, -10, 0, 30, 30 );
5117     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
5118     SetRect( &rect, 0, 0, 100, 100 );
5119     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
5120     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
5121     ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
5122     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5123     ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
5124
5125     /* test RDW_INTERNALPAINT behavior */
5126
5127     flush_sequence();
5128     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
5129     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5130     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
5131
5132     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
5133     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5134     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
5135
5136     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
5137     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5138     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
5139
5140     assert( GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
5141     UpdateWindow( hparent );
5142     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5143     flush_sequence();
5144     trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
5145     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5146     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
5147                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5148     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5149     ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
5150
5151     UpdateWindow( hparent );
5152     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5153     flush_sequence();
5154     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
5155     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5156     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
5157                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5158     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5159     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
5160
5161     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
5162     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
5163     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
5164     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5165     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
5166
5167     assert( !(GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
5168     UpdateWindow( hparent );
5169     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5170     flush_sequence();
5171     trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
5172     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5173     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
5174                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5175     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5176     ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
5177
5178     UpdateWindow( hparent );
5179     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5180     flush_sequence();
5181     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
5182     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5183     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
5184                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5185     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5186     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
5187
5188     log_all_parent_messages--;
5189     DestroyWindow( hparent );
5190     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
5191
5192     DeleteObject( hrgn );
5193     DeleteObject( hrgn2 );
5194 }
5195
5196 struct wnd_event
5197 {
5198     HWND hwnd;
5199     HANDLE event;
5200 };
5201
5202 static DWORD WINAPI thread_proc(void *param)
5203 {
5204     MSG msg;
5205     struct wnd_event *wnd_event = (struct wnd_event *)param;
5206
5207     wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
5208                                       100, 100, 200, 200, 0, 0, 0, NULL);
5209     ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
5210
5211     SetEvent(wnd_event->event);
5212
5213     while (GetMessage(&msg, 0, 0, 0))
5214     {
5215         TranslateMessage(&msg);
5216         DispatchMessage(&msg);
5217     }
5218
5219     ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
5220
5221     return 0;
5222 }
5223
5224 static void test_interthread_messages(void)
5225 {
5226     HANDLE hThread;
5227     DWORD tid;
5228     WNDPROC proc;
5229     MSG msg;
5230     char buf[256];
5231     int len, expected_len;
5232     struct wnd_event wnd_event;
5233     BOOL ret;
5234
5235     wnd_event.event = CreateEventW(NULL, 0, 0, NULL);
5236     if (!wnd_event.event)
5237     {
5238         trace("skipping interthread message test under win9x\n");
5239         return;
5240     }
5241
5242     hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
5243     ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
5244
5245     ok(WaitForSingleObject(wnd_event.event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5246
5247     CloseHandle(wnd_event.event);
5248
5249     SetLastError(0xdeadbeef);
5250     ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeded\n");
5251     ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error code %d\n", GetLastError());
5252
5253     proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
5254     ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %d\n", GetLastError());
5255
5256     expected_len = lstrlenA("window caption text");
5257     memset(buf, 0, sizeof(buf));
5258     SetLastError(0xdeadbeef);
5259     len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
5260     ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %d, len %d, expected len %d\n", GetLastError(), len, expected_len);
5261     ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
5262
5263     msg.hwnd = wnd_event.hwnd;
5264     msg.message = WM_GETTEXT;
5265     msg.wParam = sizeof(buf);
5266     msg.lParam = (LPARAM)buf;
5267     memset(buf, 0, sizeof(buf));
5268     SetLastError(0xdeadbeef);
5269     len = DispatchMessageA(&msg);
5270     ok(!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
5271        "DispatchMessageA(WM_GETTEXT) succeded on another thread window: ret %d, error %d\n", len, GetLastError());
5272
5273     /* the following test causes an exception in user.exe under win9x */
5274     msg.hwnd = wnd_event.hwnd;
5275     msg.message = WM_TIMER;
5276     msg.wParam = 0;
5277     msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
5278     SetLastError(0xdeadbeef);
5279     len = DispatchMessageA(&msg);
5280     ok(!len && GetLastError() == 0xdeadbeef,
5281        "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %d\n", len, GetLastError());
5282
5283     ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
5284     ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
5285
5286     ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5287     CloseHandle(hThread);
5288
5289     ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
5290 }
5291
5292
5293 static const struct message WmVkN[] = {
5294     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
5295     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
5296     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
5297     { WM_CHAR, wparam|lparam, 'n', 1 },
5298     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
5299     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
5300     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
5301     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
5302     { 0 }
5303 };
5304 static const struct message WmShiftVkN[] = {
5305     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
5306     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
5307     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
5308     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
5309     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
5310     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
5311     { WM_CHAR, wparam|lparam, 'N', 1 },
5312     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
5313     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
5314     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
5315     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
5316     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
5317     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
5318     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
5319     { 0 }
5320 };
5321 static const struct message WmCtrlVkN[] = {
5322     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
5323     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
5324     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
5325     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
5326     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
5327     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
5328     { WM_CHAR, wparam|lparam, 0x000e, 1 },
5329     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
5330     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
5331     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
5332     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
5333     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
5334     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
5335     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
5336     { 0 }
5337 };
5338 static const struct message WmCtrlVkN_2[] = {
5339     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
5340     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
5341     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
5342     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
5343     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
5344     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
5345     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
5346     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
5347     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
5348     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
5349     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
5350     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
5351     { 0 }
5352 };
5353 static const struct message WmAltVkN[] = {
5354     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
5355     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
5356     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
5357     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
5358     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
5359     { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
5360     { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
5361     { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
5362     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
5363     { HCBT_SYSCOMMAND, hook },
5364     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
5365     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5366     { 0x00AE, sent|defwinproc|optional }, /* XP */
5367     { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
5368     { WM_INITMENU, sent|defwinproc },
5369     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
5370     { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
5371     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
5372     { WM_CAPTURECHANGED, sent|defwinproc },
5373     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
5374     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
5375     { WM_EXITMENULOOP, sent|defwinproc },
5376     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
5377     { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
5378     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
5379     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
5380     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
5381     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
5382     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
5383     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
5384     { 0 }
5385 };
5386 static const struct message WmAltVkN_2[] = {
5387     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
5388     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
5389     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
5390     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
5391     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
5392     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
5393     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
5394     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
5395     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
5396     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
5397     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
5398     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
5399     { 0 }
5400 };
5401 static const struct message WmCtrlAltVkN[] = {
5402     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
5403     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
5404     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
5405     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
5406     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
5407     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
5408     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
5409     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
5410     { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
5411     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
5412     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
5413     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
5414     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
5415     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
5416     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
5417     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
5418     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
5419     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
5420     { 0 }
5421 };
5422 static const struct message WmCtrlShiftVkN[] = {
5423     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
5424     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
5425     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
5426     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
5427     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
5428     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
5429     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
5430     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
5431     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
5432     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
5433     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
5434     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
5435     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
5436     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
5437     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
5438     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
5439     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
5440     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
5441     { 0 }
5442 };
5443 static const struct message WmCtrlAltShiftVkN[] = {
5444     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
5445     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
5446     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
5447     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
5448     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
5449     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
5450     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
5451     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
5452     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
5453     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
5454     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
5455     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
5456     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
5457     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
5458     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
5459     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
5460     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
5461     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
5462     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
5463     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
5464     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
5465     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
5466     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
5467     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
5468     { 0 }
5469 };
5470 static const struct message WmAltPressRelease[] = {
5471     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
5472     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
5473     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
5474     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
5475     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
5476     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
5477     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
5478     { HCBT_SYSCOMMAND, hook },
5479     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
5480     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5481     { WM_INITMENU, sent|defwinproc },
5482     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
5483     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
5484     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
5485
5486     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
5487
5488     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
5489     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
5490     { WM_CAPTURECHANGED, sent|defwinproc },
5491     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
5492     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
5493     { WM_EXITMENULOOP, sent|defwinproc },
5494     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
5495     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
5496     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
5497     { 0 }
5498 };
5499 static const struct message WmAltMouseButton[] = {
5500     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
5501     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
5502     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
5503     { WM_MOUSEMOVE, wparam|optional, 0, 0 },
5504     { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
5505     { WM_LBUTTONDOWN, wparam, MK_LBUTTON, 0 },
5506     { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON, 0 },
5507     { WM_LBUTTONUP, wparam, 0, 0 },
5508     { WM_LBUTTONUP, sent|wparam, 0, 0 },
5509     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
5510     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
5511     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
5512     { 0 }
5513 };
5514 static const struct message WmF1Seq[] = {
5515     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
5516     { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
5517     { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
5518     { 0x4d, wparam|lparam, 0, 0 },
5519     { 0x4d, sent|wparam|lparam, 0, 0 },
5520     { WM_HELP, sent|defwinproc },
5521     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
5522     { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
5523     { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
5524     { 0 }
5525 };
5526 static const struct message WmVkAppsSeq[] = {
5527     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
5528     { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
5529     { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
5530     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
5531     { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
5532     { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
5533     { WM_CONTEXTMENU, lparam, /*hwnd*/0, (LPARAM)-1 },
5534     { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, (LPARAM)-1 },
5535     { 0 }
5536 };
5537
5538 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
5539 {
5540     MSG msg;
5541
5542     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
5543     {
5544         struct message log_msg;
5545
5546         trace("accel: %p, %04x, %08x, %08lx\n", msg.hwnd, msg.message, msg.wParam, msg.lParam);
5547
5548         /* ignore some unwanted messages */
5549         if (msg.message == WM_MOUSEMOVE ||
5550             msg.message == WM_GETICON ||
5551             msg.message == WM_DEVICECHANGE)
5552             continue;
5553
5554         log_msg.message = msg.message;
5555         log_msg.flags = wparam|lparam;
5556         log_msg.wParam = msg.wParam;
5557         log_msg.lParam = msg.lParam;
5558         add_message(&log_msg);
5559
5560         if (!hAccel || !TranslateAccelerator(hwnd, hAccel, &msg))
5561         {
5562             TranslateMessage(&msg);
5563             DispatchMessage(&msg);
5564         }
5565     }
5566 }
5567
5568 static void test_accelerators(void)
5569 {
5570     RECT rc;
5571     SHORT state;
5572     HACCEL hAccel;
5573     HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5574                                 100, 100, 200, 200, 0, 0, 0, NULL);
5575     BOOL ret;
5576
5577     assert(hwnd != 0);
5578     UpdateWindow(hwnd);
5579     flush_events();
5580     flush_sequence();
5581
5582     SetFocus(hwnd);
5583     ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
5584
5585     state = GetKeyState(VK_SHIFT);
5586     ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
5587     state = GetKeyState(VK_CAPITAL);
5588     ok(state == 0, "wrong CapsLock state %04x\n", state);
5589
5590     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(1));
5591     assert(hAccel != 0);
5592
5593     pump_msg_loop(hwnd, 0);
5594     flush_sequence();
5595
5596     trace("testing VK_N press/release\n");
5597     flush_sequence();
5598     keybd_event('N', 0, 0, 0);
5599     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5600     pump_msg_loop(hwnd, hAccel);
5601     ok_sequence(WmVkN, "VK_N press/release", FALSE);
5602
5603     trace("testing Shift+VK_N press/release\n");
5604     flush_sequence();
5605     keybd_event(VK_SHIFT, 0, 0, 0);
5606     keybd_event('N', 0, 0, 0);
5607     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5608     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
5609     pump_msg_loop(hwnd, hAccel);
5610     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
5611
5612     trace("testing Ctrl+VK_N press/release\n");
5613     flush_sequence();
5614     keybd_event(VK_CONTROL, 0, 0, 0);
5615     keybd_event('N', 0, 0, 0);
5616     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5617     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
5618     pump_msg_loop(hwnd, hAccel);
5619     ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
5620
5621     trace("testing Alt+VK_N press/release\n");
5622     flush_sequence();
5623     keybd_event(VK_MENU, 0, 0, 0);
5624     keybd_event('N', 0, 0, 0);
5625     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5626     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
5627     pump_msg_loop(hwnd, hAccel);
5628     ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
5629
5630     trace("testing Ctrl+Alt+VK_N press/release 1\n");
5631     flush_sequence();
5632     keybd_event(VK_CONTROL, 0, 0, 0);
5633     keybd_event(VK_MENU, 0, 0, 0);
5634     keybd_event('N', 0, 0, 0);
5635     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5636     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
5637     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
5638     pump_msg_loop(hwnd, hAccel);
5639     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
5640
5641     ret = DestroyAcceleratorTable(hAccel);
5642     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
5643
5644     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(2));
5645     assert(hAccel != 0);
5646
5647     trace("testing VK_N press/release\n");
5648     flush_sequence();
5649     keybd_event('N', 0, 0, 0);
5650     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5651     pump_msg_loop(hwnd, hAccel);
5652     ok_sequence(WmVkN, "VK_N press/release", FALSE);
5653
5654     trace("testing Shift+VK_N press/release\n");
5655     flush_sequence();
5656     keybd_event(VK_SHIFT, 0, 0, 0);
5657     keybd_event('N', 0, 0, 0);
5658     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5659     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
5660     pump_msg_loop(hwnd, hAccel);
5661     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
5662
5663     trace("testing Ctrl+VK_N press/release 2\n");
5664     flush_sequence();
5665     keybd_event(VK_CONTROL, 0, 0, 0);
5666     keybd_event('N', 0, 0, 0);
5667     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5668     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
5669     pump_msg_loop(hwnd, hAccel);
5670     ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
5671
5672     trace("testing Alt+VK_N press/release 2\n");
5673     flush_sequence();
5674     keybd_event(VK_MENU, 0, 0, 0);
5675     keybd_event('N', 0, 0, 0);
5676     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5677     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
5678     pump_msg_loop(hwnd, hAccel);
5679     ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
5680
5681     trace("testing Ctrl+Alt+VK_N press/release 2\n");
5682     flush_sequence();
5683     keybd_event(VK_CONTROL, 0, 0, 0);
5684     keybd_event(VK_MENU, 0, 0, 0);
5685     keybd_event('N', 0, 0, 0);
5686     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5687     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
5688     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
5689     pump_msg_loop(hwnd, hAccel);
5690     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
5691
5692     trace("testing Ctrl+Shift+VK_N press/release\n");
5693     flush_sequence();
5694     keybd_event(VK_CONTROL, 0, 0, 0);
5695     keybd_event(VK_SHIFT, 0, 0, 0);
5696     keybd_event('N', 0, 0, 0);
5697     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5698     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
5699     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
5700     pump_msg_loop(hwnd, hAccel);
5701     ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
5702
5703     trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
5704     flush_sequence();
5705     keybd_event(VK_CONTROL, 0, 0, 0);
5706     keybd_event(VK_MENU, 0, 0, 0);
5707     keybd_event(VK_SHIFT, 0, 0, 0);
5708     keybd_event('N', 0, 0, 0);
5709     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5710     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
5711     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
5712     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
5713     pump_msg_loop(hwnd, hAccel);
5714     ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
5715
5716     ret = DestroyAcceleratorTable(hAccel);
5717     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
5718
5719     trace("testing Alt press/release\n");
5720     flush_sequence();
5721     keybd_event(VK_MENU, 0, 0, 0);
5722     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
5723     keybd_event(VK_MENU, 0, 0, 0);
5724     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
5725     pump_msg_loop(hwnd, 0);
5726     /* this test doesn't pass in Wine for managed windows */
5727     ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
5728
5729     trace("testing Alt+MouseButton press/release\n");
5730     /* first, move mouse pointer inside of the window client area */
5731     GetClientRect(hwnd, &rc);
5732     MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
5733     rc.left += (rc.right - rc.left)/2;
5734     rc.top += (rc.bottom - rc.top)/2;
5735     SetCursorPos(rc.left, rc.top);
5736
5737     pump_msg_loop(hwnd, 0);
5738     flush_sequence();
5739     keybd_event(VK_MENU, 0, 0, 0);
5740     mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
5741     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
5742     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
5743     pump_msg_loop(hwnd, 0);
5744     ok_sequence(WmAltMouseButton, "Alt+MouseButton press/release", FALSE);
5745
5746     trace("testing VK_F1 press/release\n");
5747     keybd_event(VK_F1, 0, 0, 0);
5748     keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
5749     pump_msg_loop(hwnd, 0);
5750     ok_sequence(WmF1Seq, "F1 press/release", TRUE);
5751
5752     trace("testing VK_APPS press/release\n");
5753     keybd_event(VK_APPS, 0, 0, 0);
5754     keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
5755     pump_msg_loop(hwnd, 0);
5756     ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
5757
5758     DestroyWindow(hwnd);
5759 }
5760
5761 /************* window procedures ********************/
5762
5763 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message, 
5764                              WPARAM wParam, LPARAM lParam)
5765 {
5766     static long defwndproc_counter = 0;
5767     static long beginpaint_counter = 0;
5768     LRESULT ret;
5769     struct message msg;
5770
5771     trace("%p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
5772
5773     /* explicitly ignore WM_GETICON message */
5774     if (message == WM_GETICON) return 0;
5775
5776     switch (message)
5777     {
5778         case WM_ENABLE:
5779         {
5780             LONG style = GetWindowLongA(hwnd, GWL_STYLE);
5781             ok((BOOL)wParam == !(style & WS_DISABLED),
5782                 "wrong WS_DISABLED state: %d != %d\n", wParam, !(style & WS_DISABLED));
5783             break;
5784         }
5785
5786         case WM_CAPTURECHANGED:
5787             if (test_DestroyWindow_flag)
5788             {
5789                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
5790                 if (style & WS_CHILD)
5791                     lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
5792                 else if (style & WS_POPUP)
5793                     lParam = WND_POPUP_ID;
5794                 else
5795                     lParam = WND_PARENT_ID;
5796             }
5797             break;
5798
5799         case WM_NCDESTROY:
5800         {
5801             HWND capture;
5802
5803             ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
5804             capture = GetCapture();
5805             if (capture)
5806             {
5807                 ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
5808                 trace("current capture %p, releasing...\n", capture);
5809                 ReleaseCapture();
5810             }
5811         }
5812         /* fall through */
5813         case WM_DESTROY:
5814             if (pGetAncestor)
5815                 ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
5816             if (test_DestroyWindow_flag)
5817             {
5818                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
5819                 if (style & WS_CHILD)
5820                     lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
5821                 else if (style & WS_POPUP)
5822                     lParam = WND_POPUP_ID;
5823                 else
5824                     lParam = WND_PARENT_ID;
5825             }
5826             break;
5827
5828         /* test_accelerators() depends on this */
5829         case WM_NCHITTEST:
5830             return HTCLIENT;
5831     
5832         /* ignore */
5833         case WM_MOUSEMOVE:
5834         case WM_SETCURSOR:
5835         case WM_DEVICECHANGE:
5836             return 0;
5837
5838         case WM_WINDOWPOSCHANGING:
5839         case WM_WINDOWPOSCHANGED:
5840         {
5841             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
5842
5843             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
5844             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
5845                   winpos->hwnd, winpos->hwndInsertAfter,
5846                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
5847             dump_winpos_flags(winpos->flags);
5848
5849             /* Log only documented flags, win2k uses 0x1000 and 0x2000
5850              * in the high word for internal purposes
5851              */
5852             wParam = winpos->flags & 0xffff;
5853             /* We are not interested in the flags that don't match under XP and Win9x */
5854             wParam &= ~(SWP_NOZORDER);
5855             break;
5856         }
5857     }
5858
5859     msg.message = message;
5860     msg.flags = sent|wparam|lparam;
5861     if (defwndproc_counter) msg.flags |= defwinproc;
5862     if (beginpaint_counter) msg.flags |= beginpaint;
5863     msg.wParam = wParam;
5864     msg.lParam = lParam;
5865     add_message(&msg);
5866
5867     if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
5868     {
5869         HWND parent = GetParent(hwnd);
5870         RECT rc;
5871         MINMAXINFO *minmax = (MINMAXINFO *)lParam;
5872
5873         GetClientRect(parent, &rc);
5874         trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
5875
5876         trace("ptReserved = (%d,%d)\n"
5877               "ptMaxSize = (%d,%d)\n"
5878               "ptMaxPosition = (%d,%d)\n"
5879               "ptMinTrackSize = (%d,%d)\n"
5880               "ptMaxTrackSize = (%d,%d)\n",
5881               minmax->ptReserved.x, minmax->ptReserved.y,
5882               minmax->ptMaxSize.x, minmax->ptMaxSize.y,
5883               minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
5884               minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
5885               minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
5886
5887         ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n",
5888            minmax->ptMaxSize.x, rc.right);
5889         ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %d != %d\n",
5890            minmax->ptMaxSize.y, rc.bottom);
5891     }
5892
5893     if (message == WM_PAINT)
5894     {
5895         PAINTSTRUCT ps;
5896         beginpaint_counter++;
5897         BeginPaint( hwnd, &ps );
5898         beginpaint_counter--;
5899         EndPaint( hwnd, &ps );
5900         return 0;
5901     }
5902
5903     defwndproc_counter++;
5904     ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam) 
5905                   : DefWindowProcA(hwnd, message, wParam, lParam);
5906     defwndproc_counter--;
5907
5908     return ret;
5909 }
5910
5911 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5912 {
5913     return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
5914 }
5915
5916 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5917 {
5918     return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
5919 }
5920
5921 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5922 {
5923     static long defwndproc_counter = 0;
5924     LRESULT ret;
5925     struct message msg;
5926
5927     trace("popup: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
5928
5929     /* explicitly ignore WM_GETICON message */
5930     if (message == WM_GETICON) return 0;
5931
5932     msg.message = message;
5933     msg.flags = sent|wparam|lparam;
5934     if (defwndproc_counter) msg.flags |= defwinproc;
5935     msg.wParam = wParam;
5936     msg.lParam = lParam;
5937     add_message(&msg);
5938
5939     if (message == WM_CREATE)
5940     {
5941         DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
5942         SetWindowLongA(hwnd, GWL_STYLE, style);
5943     }
5944
5945     defwndproc_counter++;
5946     ret = DefWindowProcA(hwnd, message, wParam, lParam);
5947     defwndproc_counter--;
5948
5949     return ret;
5950 }
5951
5952 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5953 {
5954     static long defwndproc_counter = 0;
5955     static long beginpaint_counter = 0;
5956     LRESULT ret;
5957     struct message msg;
5958
5959     trace("parent: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
5960
5961     /* explicitly ignore WM_GETICON message */
5962     if (message == WM_GETICON) return 0;
5963
5964     if (log_all_parent_messages ||
5965         message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
5966         message == WM_SETFOCUS || message == WM_KILLFOCUS ||
5967         message == WM_ENABLE || message == WM_ENTERIDLE ||
5968         message == WM_IME_SETCONTEXT)
5969     {
5970         switch (message)
5971         {
5972             /* ignore */
5973             case WM_NCHITTEST:
5974                 return HTCLIENT;
5975             case WM_SETCURSOR:
5976             case WM_MOUSEMOVE:
5977                 return 0;
5978
5979             case WM_ERASEBKGND:
5980             {
5981                 RECT rc;
5982                 INT ret = GetClipBox((HDC)wParam, &rc);
5983
5984                 trace("WM_ERASEBKGND: GetClipBox()=%d, (%d,%d-%d,%d)\n",
5985                        ret, rc.left, rc.top, rc.right, rc.bottom);
5986                 break;
5987             }
5988
5989             case WM_WINDOWPOSCHANGING:
5990             case WM_WINDOWPOSCHANGED:
5991             {
5992                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
5993
5994                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
5995                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
5996                       winpos->hwnd, winpos->hwndInsertAfter,
5997                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
5998                 dump_winpos_flags(winpos->flags);
5999
6000                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
6001                  * in the high word for internal purposes
6002                  */
6003                 wParam = winpos->flags & 0xffff;
6004                 /* We are not interested in the flags that don't match under XP and Win9x */
6005                 wParam &= ~(SWP_NOZORDER);
6006                 break;
6007             }
6008         }
6009
6010         msg.message = message;
6011         msg.flags = sent|parent|wparam|lparam;
6012         if (defwndproc_counter) msg.flags |= defwinproc;
6013         if (beginpaint_counter) msg.flags |= beginpaint;
6014         msg.wParam = wParam;
6015         msg.lParam = lParam;
6016         add_message(&msg);
6017     }
6018
6019     if (message == WM_PAINT)
6020     {
6021         PAINTSTRUCT ps;
6022         beginpaint_counter++;
6023         BeginPaint( hwnd, &ps );
6024         beginpaint_counter--;
6025         EndPaint( hwnd, &ps );
6026         return 0;
6027     }
6028
6029     defwndproc_counter++;
6030     ret = DefWindowProcA(hwnd, message, wParam, lParam);
6031     defwndproc_counter--;
6032
6033     return ret;
6034 }
6035
6036 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6037 {
6038     static long defwndproc_counter = 0;
6039     LRESULT ret;
6040     struct message msg;
6041
6042     trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
6043
6044     /* explicitly ignore WM_GETICON message */
6045     if (message == WM_GETICON) return 0;
6046
6047     if (test_def_id)
6048     {
6049         DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
6050         ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
6051         if (after_end_dialog)
6052             ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
6053         else
6054             ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
6055     }
6056
6057     switch (message)
6058     {
6059         case WM_WINDOWPOSCHANGING:
6060         case WM_WINDOWPOSCHANGED:
6061         {
6062             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
6063
6064             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
6065             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
6066                   winpos->hwnd, winpos->hwndInsertAfter,
6067                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
6068             dump_winpos_flags(winpos->flags);
6069
6070             /* Log only documented flags, win2k uses 0x1000 and 0x2000
6071              * in the high word for internal purposes
6072              */
6073             wParam = winpos->flags & 0xffff;
6074             /* We are not interested in the flags that don't match under XP and Win9x */
6075             wParam &= ~(SWP_NOZORDER);
6076             break;
6077         }
6078     }
6079
6080     msg.message = message;
6081     msg.flags = sent|wparam|lparam;
6082     if (defwndproc_counter) msg.flags |= defwinproc;
6083     msg.wParam = wParam;
6084     msg.lParam = lParam;
6085     add_message(&msg);
6086
6087     defwndproc_counter++;
6088     ret = DefDlgProcA(hwnd, message, wParam, lParam);
6089     defwndproc_counter--;
6090
6091     return ret;
6092 }
6093
6094 static void dump_winpos_flags(UINT flags)
6095 {
6096     if (!winetest_debug) return;
6097
6098     if (flags & SWP_SHOWWINDOW) printf("|SWP_SHOWWINDOW");
6099     if (flags & SWP_HIDEWINDOW) printf("|SWP_HIDEWINDOW");
6100     if (flags & SWP_NOACTIVATE) printf("|SWP_NOACTIVATE");
6101     if (flags & SWP_FRAMECHANGED) printf("|SWP_FRAMECHANGED");
6102     if (flags & SWP_NOCOPYBITS) printf("|SWP_NOCOPYBITS");
6103     if (flags & SWP_NOOWNERZORDER) printf("|SWP_NOOWNERZORDER");
6104     if (flags & SWP_NOSENDCHANGING) printf("|SWP_NOSENDCHANGING");
6105     if (flags & SWP_DEFERERASE) printf("|SWP_DEFERERASE");
6106     if (flags & SWP_ASYNCWINDOWPOS) printf("|SWP_ASYNCWINDOWPOS");
6107     if (flags & SWP_NOZORDER) printf("|SWP_NOZORDER");
6108     if (flags & SWP_NOREDRAW) printf("|SWP_NOREDRAW");
6109     if (flags & SWP_NOSIZE) printf("|SWP_NOSIZE");
6110     if (flags & SWP_NOMOVE) printf("|SWP_NOMOVE");
6111     if (flags & SWP_NOCLIENTSIZE) printf("|SWP_NOCLIENTSIZE");
6112     if (flags & SWP_NOCLIENTMOVE) printf("|SWP_NOCLIENTMOVE");
6113
6114 #define DUMPED_FLAGS \
6115     (SWP_NOSIZE | \
6116     SWP_NOMOVE | \
6117     SWP_NOZORDER | \
6118     SWP_NOREDRAW | \
6119     SWP_NOACTIVATE | \
6120     SWP_FRAMECHANGED | \
6121     SWP_SHOWWINDOW | \
6122     SWP_HIDEWINDOW | \
6123     SWP_NOCOPYBITS | \
6124     SWP_NOOWNERZORDER | \
6125     SWP_NOSENDCHANGING | \
6126     SWP_DEFERERASE | \
6127     SWP_ASYNCWINDOWPOS | \
6128     SWP_NOCLIENTSIZE | \
6129     SWP_NOCLIENTMOVE)
6130
6131     if(flags & ~DUMPED_FLAGS) printf("|0x%04x", flags & ~DUMPED_FLAGS);
6132     printf("\n");
6133 #undef DUMPED_FLAGS
6134 }
6135
6136 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6137 {
6138     static long defwndproc_counter = 0;
6139     LRESULT ret;
6140     struct message msg;
6141
6142     /* log only specific messages we are interested in */
6143     switch (message)
6144     {
6145 #if 0 /* probably log these as well */
6146     case WM_ACTIVATE:
6147     case WM_SETFOCUS:
6148     case WM_KILLFOCUS:
6149 #endif
6150     case WM_SHOWWINDOW:
6151         trace("WM_SHOWWINDOW %d\n", wParam);
6152         break;
6153     case WM_SIZE:
6154         trace("WM_SIZE %d\n", wParam);
6155         break;
6156     case WM_MOVE:
6157         trace("WM_MOVE\n");
6158         break;
6159     case WM_GETMINMAXINFO:
6160         trace("WM_GETMINMAXINFO\n");
6161         break;
6162
6163     case WM_WINDOWPOSCHANGING:
6164     case WM_WINDOWPOSCHANGED:
6165     {
6166         WINDOWPOS *winpos = (WINDOWPOS *)lParam;
6167
6168         trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
6169         trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
6170               winpos->hwnd, winpos->hwndInsertAfter,
6171               winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
6172         trace("flags: ");
6173         dump_winpos_flags(winpos->flags);
6174
6175         /* Log only documented flags, win2k uses 0x1000 and 0x2000
6176          * in the high word for internal purposes
6177          */
6178         wParam = winpos->flags & 0xffff;
6179         /* We are not interested in the flags that don't match under XP and Win9x */
6180         wParam &= ~(SWP_NOZORDER);
6181         break;
6182     }
6183
6184     default: /* ignore */
6185         /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
6186         return DefWindowProcA(hwnd, message, wParam, lParam);
6187     }
6188
6189     msg.message = message;
6190     msg.flags = sent|wparam|lparam;
6191     if (defwndproc_counter) msg.flags |= defwinproc;
6192     msg.wParam = wParam;
6193     msg.lParam = lParam;
6194     add_message(&msg);
6195
6196     defwndproc_counter++;
6197     ret = DefWindowProcA(hwnd, message, wParam, lParam);
6198     defwndproc_counter--;
6199
6200     return ret;
6201 }
6202
6203 static BOOL RegisterWindowClasses(void)
6204 {
6205     WNDCLASSA cls;
6206
6207     cls.style = 0;
6208     cls.lpfnWndProc = MsgCheckProcA;
6209     cls.cbClsExtra = 0;
6210     cls.cbWndExtra = 0;
6211     cls.hInstance = GetModuleHandleA(0);
6212     cls.hIcon = 0;
6213     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
6214     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
6215     cls.lpszMenuName = NULL;
6216     cls.lpszClassName = "TestWindowClass";
6217     if(!RegisterClassA(&cls)) return FALSE;
6218
6219     cls.lpfnWndProc = ShowWindowProcA;
6220     cls.lpszClassName = "ShowWindowClass";
6221     if(!RegisterClassA(&cls)) return FALSE;
6222
6223     cls.lpfnWndProc = PopupMsgCheckProcA;
6224     cls.lpszClassName = "TestPopupClass";
6225     if(!RegisterClassA(&cls)) return FALSE;
6226
6227     cls.lpfnWndProc = ParentMsgCheckProcA;
6228     cls.lpszClassName = "TestParentClass";
6229     if(!RegisterClassA(&cls)) return FALSE;
6230
6231     cls.lpfnWndProc = DefWindowProcA;
6232     cls.lpszClassName = "SimpleWindowClass";
6233     if(!RegisterClassA(&cls)) return FALSE;
6234
6235     cls.style = CS_NOCLOSE;
6236     cls.lpszClassName = "NoCloseWindowClass";
6237     if(!RegisterClassA(&cls)) return FALSE;
6238
6239     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
6240     cls.style = 0;
6241     cls.hInstance = GetModuleHandleA(0);
6242     cls.hbrBackground = 0;
6243     cls.lpfnWndProc = TestDlgProcA;
6244     cls.lpszClassName = "TestDialogClass";
6245     if(!RegisterClassA(&cls)) return FALSE;
6246
6247     return TRUE;
6248 }
6249
6250 static HHOOK hCBT_hook;
6251 static DWORD cbt_hook_thread_id;
6252
6253 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
6254
6255     static const char * const CBT_code_name[10] = {
6256         "HCBT_MOVESIZE",
6257         "HCBT_MINMAX",
6258         "HCBT_QS",
6259         "HCBT_CREATEWND",
6260         "HCBT_DESTROYWND",
6261         "HCBT_ACTIVATE",
6262         "HCBT_CLICKSKIPPED",
6263         "HCBT_KEYSKIPPED",
6264         "HCBT_SYSCOMMAND",
6265         "HCBT_SETFOCUS" };
6266     const char *code_name = (nCode >= 0 && nCode <= HCBT_SETFOCUS) ? CBT_code_name[nCode] : "Unknown";
6267     HWND hwnd;
6268     char buf[256];
6269
6270     trace("CBT: %d (%s), %08x, %08lx\n", nCode, code_name, wParam, lParam);
6271
6272     ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
6273
6274     if (nCode == HCBT_CLICKSKIPPED)
6275     {
6276         /* ignore this event, XP sends it a lot when switching focus between windows */
6277         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
6278     }
6279
6280     if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
6281     {
6282         struct message msg;
6283
6284         msg.message = nCode;
6285         msg.flags = hook|wparam|lparam;
6286         msg.wParam = wParam;
6287         msg.lParam = lParam;
6288         add_message(&msg);
6289
6290         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
6291     }
6292
6293     if (nCode == HCBT_DESTROYWND)
6294     {
6295         if (test_DestroyWindow_flag)
6296         {
6297             DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
6298             if (style & WS_CHILD)
6299                 lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
6300             else if (style & WS_POPUP)
6301                 lParam = WND_POPUP_ID;
6302             else
6303                 lParam = WND_PARENT_ID;
6304         }
6305     }
6306
6307     /* Log also SetFocus(0) calls */
6308     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
6309
6310     if (GetClassNameA(hwnd, buf, sizeof(buf)))
6311     {
6312         if (!lstrcmpiA(buf, "TestWindowClass") ||
6313             !lstrcmpiA(buf, "ShowWindowClass") ||
6314             !lstrcmpiA(buf, "TestParentClass") ||
6315             !lstrcmpiA(buf, "TestPopupClass") ||
6316             !lstrcmpiA(buf, "SimpleWindowClass") ||
6317             !lstrcmpiA(buf, "TestDialogClass") ||
6318             !lstrcmpiA(buf, "MDI_frame_class") ||
6319             !lstrcmpiA(buf, "MDI_client_class") ||
6320             !lstrcmpiA(buf, "MDI_child_class") ||
6321             !lstrcmpiA(buf, "my_button_class") ||
6322             !lstrcmpiA(buf, "my_edit_class") ||
6323             !lstrcmpiA(buf, "static") ||
6324             !lstrcmpiA(buf, "MyDialogClass") ||
6325             !lstrcmpiA(buf, "#32770"))
6326         {
6327             struct message msg;
6328
6329             msg.message = nCode;
6330             msg.flags = hook|wparam|lparam;
6331             msg.wParam = wParam;
6332             msg.lParam = lParam;
6333             add_message(&msg);
6334         }
6335     }
6336     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
6337 }
6338
6339 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
6340                                     DWORD event,
6341                                     HWND hwnd,
6342                                     LONG object_id,
6343                                     LONG child_id,
6344                                     DWORD thread_id,
6345                                     DWORD event_time)
6346 {
6347     char buf[256];
6348
6349     trace("WEH:%p,event %08x,hwnd %p,obj %08x,id %08x,thread %08x,time %08x\n",
6350            hevent, event, hwnd, object_id, child_id, thread_id, event_time);
6351
6352     ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
6353
6354     /* ignore mouse cursor events */
6355     if (object_id == OBJID_CURSOR) return;
6356
6357     if (!hwnd || GetClassNameA(hwnd, buf, sizeof(buf)))
6358     {
6359         if (!hwnd ||
6360             !lstrcmpiA(buf, "TestWindowClass") ||
6361             !lstrcmpiA(buf, "TestParentClass") ||
6362             !lstrcmpiA(buf, "TestPopupClass") ||
6363             !lstrcmpiA(buf, "SimpleWindowClass") ||
6364             !lstrcmpiA(buf, "TestDialogClass") ||
6365             !lstrcmpiA(buf, "MDI_frame_class") ||
6366             !lstrcmpiA(buf, "MDI_client_class") ||
6367             !lstrcmpiA(buf, "MDI_child_class") ||
6368             !lstrcmpiA(buf, "my_button_class") ||
6369             !lstrcmpiA(buf, "my_edit_class") ||
6370             !lstrcmpiA(buf, "static") ||
6371             !lstrcmpiA(buf, "MyDialogClass") ||
6372             !lstrcmpiA(buf, "#32770"))
6373         {
6374             struct message msg;
6375
6376             msg.message = event;
6377             msg.flags = winevent_hook|wparam|lparam;
6378             msg.wParam = object_id;
6379             msg.lParam = child_id;
6380             add_message(&msg);
6381         }
6382     }
6383 }
6384
6385 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
6386 static const WCHAR wszAnsi[] = {'U',0};
6387
6388 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
6389 {
6390     switch (uMsg)
6391     {
6392     case CB_FINDSTRINGEXACT:
6393         trace("String: %p\n", (LPCWSTR)lParam);
6394         if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
6395             return 1;
6396         if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
6397             return 0;
6398         return -1;
6399     }
6400     return DefWindowProcW(hwnd, uMsg, wParam, lParam);
6401 }
6402
6403 static const struct message WmGetTextLengthAfromW[] = {
6404     { WM_GETTEXTLENGTH, sent },
6405     { WM_GETTEXT, sent },
6406     { 0 }
6407 };
6408
6409 static const WCHAR testWindowClassW[] = 
6410 { 'T','e','s','t','W','i','n','d','o','w','C','l','a','s','s','W',0 };
6411
6412 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
6413
6414 /* dummy window proc for WM_GETTEXTLENGTH test */
6415 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
6416 {
6417     switch(msg)
6418     {
6419     case WM_GETTEXTLENGTH:
6420         return lstrlenW(dummy_window_text) + 37;  /* some random length */
6421     case WM_GETTEXT:
6422         lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
6423         return lstrlenW( (LPWSTR)lp );
6424     default:
6425         return DefWindowProcW( hwnd, msg, wp, lp );
6426     }
6427 }
6428
6429 static void test_message_conversion(void)
6430 {
6431     static const WCHAR wszMsgConversionClass[] =
6432         {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
6433     WNDCLASSW cls;
6434     LRESULT lRes;
6435     HWND hwnd;
6436     WNDPROC wndproc, newproc;
6437     BOOL ret;
6438
6439     cls.style = 0;
6440     cls.lpfnWndProc = MsgConversionProcW;
6441     cls.cbClsExtra = 0;
6442     cls.cbWndExtra = 0;
6443     cls.hInstance = GetModuleHandleW(NULL);
6444     cls.hIcon = NULL;
6445     cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
6446     cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
6447     cls.lpszMenuName = NULL;
6448     cls.lpszClassName = wszMsgConversionClass;
6449     /* this call will fail on Win9x, but that doesn't matter as this test is
6450      * meaningless on those platforms */
6451     if(!RegisterClassW(&cls)) return;
6452
6453     cls.style = 0;
6454     cls.lpfnWndProc = MsgCheckProcW;
6455     cls.cbClsExtra = 0;
6456     cls.cbWndExtra = 0;
6457     cls.hInstance = GetModuleHandleW(0);
6458     cls.hIcon = 0;
6459     cls.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
6460     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
6461     cls.lpszMenuName = NULL;
6462     cls.lpszClassName = testWindowClassW;
6463     if(!RegisterClassW(&cls)) return;
6464
6465     hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
6466                            100, 100, 200, 200, 0, 0, 0, NULL);
6467     ok(hwnd != NULL, "Window creation failed\n");
6468
6469     /* {W, A} -> A */
6470
6471     wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
6472     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6473     ok(lRes == 0, "String should have been converted\n");
6474     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6475     ok(lRes == 1, "String shouldn't have been converted\n");
6476
6477     /* {W, A} -> W */
6478
6479     wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
6480     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6481     ok(lRes == 1, "String shouldn't have been converted\n");
6482     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6483     ok(lRes == 1, "String shouldn't have been converted\n");
6484
6485     /* Synchronous messages */
6486
6487     lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6488     ok(lRes == 0, "String should have been converted\n");
6489     lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6490     ok(lRes == 1, "String shouldn't have been converted\n");
6491
6492     /* Asynchronous messages */
6493
6494     SetLastError(0);
6495     lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6496     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6497         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6498     SetLastError(0);
6499     lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6500     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6501         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6502     SetLastError(0);
6503     lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6504     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6505         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6506     SetLastError(0);
6507     lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6508     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6509         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6510     SetLastError(0);
6511     lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6512     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6513         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6514     SetLastError(0);
6515     lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6516     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6517         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6518     SetLastError(0);
6519     lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
6520     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6521         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6522     SetLastError(0);
6523     lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
6524     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6525         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6526
6527     /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
6528
6529     hwnd = CreateWindowW (testWindowClassW, wszUnicode,
6530                           WS_OVERLAPPEDWINDOW,
6531                           100, 100, 200, 200, 0, 0, 0, NULL);
6532     assert(hwnd);
6533     flush_sequence();
6534     lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
6535     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
6536     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
6537         "got bad length %ld\n", lRes );
6538
6539     flush_sequence();
6540     lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
6541                             hwnd, WM_GETTEXTLENGTH, 0, 0);
6542     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
6543     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
6544         "got bad length %ld\n", lRes );
6545
6546     wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
6547     newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
6548     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
6549     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
6550                                      NULL, 0, NULL, NULL ),
6551         "got bad length %ld\n", lRes );
6552
6553     SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc );  /* restore old wnd proc */
6554     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
6555     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
6556                                      NULL, 0, NULL, NULL ),
6557         "got bad length %ld\n", lRes );
6558
6559     ret = DestroyWindow(hwnd);
6560     ok( ret, "DestroyWindow() error %d\n", GetLastError());
6561 }
6562
6563 struct timer_info
6564 {
6565     HWND hWnd;
6566     HANDLE handles[2];
6567     DWORD id;
6568 };
6569
6570 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT id, DWORD dwTime)
6571 {
6572 }
6573
6574 #define TIMER_ID  0x19
6575
6576 static DWORD WINAPI timer_thread_proc(LPVOID x)
6577 {
6578     struct timer_info *info = x;
6579     DWORD r;
6580
6581     r = KillTimer(info->hWnd, 0x19);
6582     ok(r,"KillTimer failed in thread\n");
6583     r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
6584     ok(r,"SetTimer failed in thread\n");
6585     ok(r==TIMER_ID,"SetTimer id different\n");
6586     r = SetEvent(info->handles[0]);
6587     ok(r,"SetEvent failed in thread\n");
6588     return 0;
6589 }
6590
6591 static void test_timers(void)
6592 {
6593     struct timer_info info;
6594     DWORD id;
6595
6596     info.hWnd = CreateWindow ("TestWindowClass", NULL,
6597        WS_OVERLAPPEDWINDOW ,
6598        CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
6599        NULL, NULL, 0);
6600
6601     info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
6602     ok(info.id, "SetTimer failed\n");
6603     ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
6604     info.handles[0] = CreateEvent(NULL,0,0,NULL);
6605     info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
6606
6607     WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
6608
6609     WaitForSingleObject(info.handles[1], INFINITE);
6610
6611     CloseHandle(info.handles[0]);
6612     CloseHandle(info.handles[1]);
6613
6614     ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
6615
6616     ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
6617 }
6618
6619 /* Various win events with arbitrary parameters */
6620 static const struct message WmWinEventsSeq[] = {
6621     { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
6622     { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
6623     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
6624     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
6625     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
6626     { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
6627     { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
6628     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
6629     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
6630     /* our win event hook ignores OBJID_CURSOR events */
6631     /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
6632     { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
6633     { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
6634     { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
6635     { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
6636     { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
6637     { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
6638     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
6639     { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
6640     { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
6641     { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
6642     { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
6643     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
6644     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
6645     { 0 }
6646 };
6647 static const struct message WmWinEventCaretSeq[] = {
6648     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
6649     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
6650     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
6651     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
6652     { 0 }
6653 };
6654 static const struct message WmWinEventCaretSeq_2[] = {
6655     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
6656     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
6657     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
6658     { 0 }
6659 };
6660 static const struct message WmWinEventAlertSeq[] = {
6661     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
6662     { 0 }
6663 };
6664 static const struct message WmWinEventAlertSeq_2[] = {
6665     /* create window in the thread proc */
6666     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
6667     /* our test event */
6668     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
6669     { 0 }
6670 };
6671 static const struct message WmGlobalHookSeq_1[] = {
6672     /* create window in the thread proc */
6673     { HCBT_CREATEWND, hook|lparam, 0, 2 },
6674     /* our test events */
6675     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
6676     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
6677     { 0 }
6678 };
6679 static const struct message WmGlobalHookSeq_2[] = {
6680     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
6681     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
6682     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
6683     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
6684     { 0 }
6685 };
6686
6687 static const struct message WmMouseLLHookSeq[] = {
6688     { WM_MOUSEMOVE, hook },
6689     { WM_LBUTTONUP, hook },
6690     { WM_MOUSEMOVE, hook },
6691     { 0 }
6692 };
6693
6694 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
6695                                          DWORD event,
6696                                          HWND hwnd,
6697                                          LONG object_id,
6698                                          LONG child_id,
6699                                          DWORD thread_id,
6700                                          DWORD event_time)
6701 {
6702     char buf[256];
6703
6704     trace("WEH_2:%p,event %08x,hwnd %p,obj %08x,id %08x,thread %08x,time %08x\n",
6705            hevent, event, hwnd, object_id, child_id, thread_id, event_time);
6706
6707     if (GetClassNameA(hwnd, buf, sizeof(buf)))
6708     {
6709         if (!lstrcmpiA(buf, "TestWindowClass") ||
6710             !lstrcmpiA(buf, "static"))
6711         {
6712             struct message msg;
6713
6714             msg.message = event;
6715             msg.flags = winevent_hook|wparam|lparam;
6716             msg.wParam = object_id;
6717             msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
6718             add_message(&msg);
6719         }
6720     }
6721 }
6722
6723 static HHOOK hCBT_global_hook;
6724 static DWORD cbt_global_hook_thread_id;
6725
6726 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
6727
6728     HWND hwnd;
6729     char buf[256];
6730
6731     trace("CBT_2: %d, %08x, %08lx\n", nCode, wParam, lParam);
6732
6733     if (nCode == HCBT_SYSCOMMAND)
6734     {
6735         struct message msg;
6736
6737         msg.message = nCode;
6738         msg.flags = hook|wparam|lparam;
6739         msg.wParam = wParam;
6740         msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
6741         add_message(&msg);
6742
6743         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
6744     }
6745     /* WH_MOUSE_LL hook */
6746     if (nCode == HC_ACTION)
6747     {
6748         struct message msg;
6749         MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
6750
6751         /* we can't test for real mouse events */
6752         if (mhll->flags & LLMHF_INJECTED)
6753         {
6754             msg.message = wParam;
6755             msg.flags = hook;
6756             add_message(&msg);
6757         }
6758         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
6759     }
6760
6761     /* Log also SetFocus(0) calls */
6762     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
6763
6764     if (GetClassNameA(hwnd, buf, sizeof(buf)))
6765     {
6766         if (!lstrcmpiA(buf, "TestWindowClass") ||
6767             !lstrcmpiA(buf, "static"))
6768         {
6769             struct message msg;
6770
6771             msg.message = nCode;
6772             msg.flags = hook|wparam|lparam;
6773             msg.wParam = wParam;
6774             msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
6775             add_message(&msg);
6776         }
6777     }
6778     return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
6779 }
6780
6781 static DWORD WINAPI win_event_global_thread_proc(void *param)
6782 {
6783     HWND hwnd;
6784     MSG msg;
6785     HANDLE hevent = *(HANDLE *)param;
6786     HMODULE user32 = GetModuleHandleA("user32.dll");
6787     FARPROC pNotifyWinEvent = GetProcAddress(user32, "NotifyWinEvent");
6788
6789     assert(pNotifyWinEvent);
6790
6791     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
6792     assert(hwnd);
6793     trace("created thread window %p\n", hwnd);
6794
6795     *(HWND *)param = hwnd;
6796
6797     flush_sequence();
6798     /* this event should be received only by our new hook proc,
6799      * an old one does not expect an event from another thread.
6800      */
6801     pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
6802     SetEvent(hevent);
6803
6804     while (GetMessage(&msg, 0, 0, 0))
6805     {
6806         TranslateMessage(&msg);
6807         DispatchMessage(&msg);
6808     }
6809     return 0;
6810 }
6811
6812 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
6813 {
6814     HWND hwnd;
6815     MSG msg;
6816     HANDLE hevent = *(HANDLE *)param;
6817
6818     flush_sequence();
6819     /* these events should be received only by our new hook proc,
6820      * an old one does not expect an event from another thread.
6821      */
6822
6823     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
6824     assert(hwnd);
6825     trace("created thread window %p\n", hwnd);
6826
6827     *(HWND *)param = hwnd;
6828
6829     /* Windows doesn't like when a thread plays games with the focus,
6830        that leads to all kinds of misbehaviours and failures to activate
6831        a window. So, better keep next lines commented out.
6832     SetFocus(0);
6833     SetFocus(hwnd);*/
6834
6835     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
6836     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
6837
6838     SetEvent(hevent);
6839
6840     while (GetMessage(&msg, 0, 0, 0))
6841     {
6842         TranslateMessage(&msg);
6843         DispatchMessage(&msg);
6844     }
6845     return 0;
6846 }
6847
6848 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
6849 {
6850     HWND hwnd;
6851     MSG msg;
6852     HANDLE hevent = *(HANDLE *)param;
6853
6854     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
6855     assert(hwnd);
6856     trace("created thread window %p\n", hwnd);
6857
6858     *(HWND *)param = hwnd;
6859
6860     flush_sequence();
6861
6862     /* Windows doesn't like when a thread plays games with the focus,
6863      * that leads to all kinds of misbehaviours and failures to activate
6864      * a window. So, better don't generate a mouse click message below.
6865      */
6866     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
6867     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
6868     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
6869
6870     SetEvent(hevent);
6871     while (GetMessage(&msg, 0, 0, 0))
6872     {
6873         TranslateMessage(&msg);
6874         DispatchMessage(&msg);
6875     }
6876     return 0;
6877 }
6878
6879 static void test_winevents(void)
6880 {
6881     BOOL ret;
6882     MSG msg;
6883     HWND hwnd, hwnd2;
6884     UINT i;
6885     HANDLE hthread, hevent;
6886     DWORD tid;
6887     HWINEVENTHOOK hhook;
6888     const struct message *events = WmWinEventsSeq;
6889     HMODULE user32 = GetModuleHandleA("user32.dll");
6890     FARPROC pSetWinEventHook = GetProcAddress(user32, "SetWinEventHook");
6891     FARPROC pUnhookWinEvent = GetProcAddress(user32, "UnhookWinEvent");
6892     FARPROC pNotifyWinEvent = GetProcAddress(user32, "NotifyWinEvent");
6893
6894     hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
6895                            WS_OVERLAPPEDWINDOW,
6896                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
6897                            NULL, NULL, 0);
6898     assert(hwnd);
6899
6900     /****** start of global hook test *************/
6901     hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
6902     assert(hCBT_global_hook);
6903
6904     hevent = CreateEventA(NULL, 0, 0, NULL);
6905     assert(hevent);
6906     hwnd2 = (HWND)hevent;
6907
6908     hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
6909     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
6910
6911     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6912
6913     ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
6914
6915     flush_sequence();
6916     /* this one should be received only by old hook proc */
6917     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
6918     /* this one should be received only by old hook proc */
6919     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
6920
6921     ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
6922
6923     ret = UnhookWindowsHookEx(hCBT_global_hook);
6924     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
6925
6926     PostThreadMessageA(tid, WM_QUIT, 0, 0);
6927     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6928     CloseHandle(hthread);
6929     CloseHandle(hevent);
6930     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
6931     /****** end of global hook test *************/
6932
6933     if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
6934     {
6935         ok(DestroyWindow(hwnd), "failed to destroy window\n");
6936         return;
6937     }
6938
6939     flush_sequence();
6940
6941     if (0)
6942     {
6943     /* this test doesn't pass under Win9x */
6944     /* win2k ignores events with hwnd == 0 */
6945     SetLastError(0xdeadbeef);
6946     pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
6947     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
6948        GetLastError() == 0xdeadbeef, /* Win9x */
6949        "unexpected error %d\n", GetLastError());
6950     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
6951     }
6952
6953     for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++)
6954         pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
6955
6956     ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
6957
6958     /****** start of event filtering test *************/
6959     hhook = (HWINEVENTHOOK)pSetWinEventHook(
6960         EVENT_OBJECT_SHOW, /* 0x8002 */
6961         EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
6962         GetModuleHandleA(0), win_event_global_hook_proc,
6963         GetCurrentProcessId(), 0,
6964         WINEVENT_INCONTEXT);
6965     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
6966
6967     hevent = CreateEventA(NULL, 0, 0, NULL);
6968     assert(hevent);
6969     hwnd2 = (HWND)hevent;
6970
6971     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
6972     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
6973
6974     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6975
6976     ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
6977
6978     flush_sequence();
6979     /* this one should be received only by old hook proc */
6980     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
6981     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
6982     /* this one should be received only by old hook proc */
6983     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
6984
6985     ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
6986
6987     ret = pUnhookWinEvent(hhook);
6988     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
6989
6990     PostThreadMessageA(tid, WM_QUIT, 0, 0);
6991     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6992     CloseHandle(hthread);
6993     CloseHandle(hevent);
6994     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
6995     /****** end of event filtering test *************/
6996
6997     /****** start of out of context event test *************/
6998     hhook = (HWINEVENTHOOK)pSetWinEventHook(
6999         EVENT_MIN, EVENT_MAX,
7000         0, win_event_global_hook_proc,
7001         GetCurrentProcessId(), 0,
7002         WINEVENT_OUTOFCONTEXT);
7003     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
7004
7005     hevent = CreateEventA(NULL, 0, 0, NULL);
7006     assert(hevent);
7007     hwnd2 = (HWND)hevent;
7008
7009     flush_sequence();
7010
7011     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
7012     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7013
7014     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7015
7016     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
7017     /* process pending winevent messages */
7018     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
7019     ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
7020
7021     flush_sequence();
7022     /* this one should be received only by old hook proc */
7023     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
7024     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
7025     /* this one should be received only by old hook proc */
7026     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
7027
7028     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
7029     /* process pending winevent messages */
7030     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
7031     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
7032
7033     ret = pUnhookWinEvent(hhook);
7034     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
7035
7036     PostThreadMessageA(tid, WM_QUIT, 0, 0);
7037     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7038     CloseHandle(hthread);
7039     CloseHandle(hevent);
7040     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7041     /****** end of out of context event test *************/
7042
7043     /****** start of MOUSE_LL hook test *************/
7044     hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
7045     /* WH_MOUSE_LL is not supported on Win9x platforms */
7046     if (!hCBT_global_hook)
7047     {
7048         trace("Skipping WH_MOUSE_LL test on this platform\n");
7049         goto skip_mouse_ll_hook_test;
7050     }
7051
7052     hevent = CreateEventA(NULL, 0, 0, NULL);
7053     assert(hevent);
7054     hwnd2 = (HWND)hevent;
7055
7056     hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
7057     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7058
7059     while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
7060         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
7061
7062     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
7063     flush_sequence();
7064
7065     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
7066     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
7067     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
7068
7069     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
7070
7071     ret = UnhookWindowsHookEx(hCBT_global_hook);
7072     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
7073
7074     PostThreadMessageA(tid, WM_QUIT, 0, 0);
7075     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7076     CloseHandle(hthread);
7077     CloseHandle(hevent);
7078     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7079     /****** end of MOUSE_LL hook test *************/
7080 skip_mouse_ll_hook_test:
7081
7082     ok(DestroyWindow(hwnd), "failed to destroy window\n");
7083 }
7084
7085 static void test_set_hook(void)
7086 {
7087     BOOL ret;
7088     HHOOK hhook;
7089     HWINEVENTHOOK hwinevent_hook;
7090     HMODULE user32 = GetModuleHandleA("user32.dll");
7091     FARPROC pSetWinEventHook = GetProcAddress(user32, "SetWinEventHook");
7092     FARPROC pUnhookWinEvent = GetProcAddress(user32, "UnhookWinEvent");
7093
7094     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
7095     ok(hhook != 0, "local hook does not require hModule set to 0\n");
7096     UnhookWindowsHookEx(hhook);
7097
7098     if (0)
7099     {
7100     /* this test doesn't pass under Win9x: BUG! */
7101     SetLastError(0xdeadbeef);
7102     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
7103     ok(!hhook, "global hook requires hModule != 0\n");
7104     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
7105     }
7106
7107     SetLastError(0xdeadbeef);
7108     hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
7109     ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
7110     ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
7111        GetLastError() == 0xdeadbeef, /* Win9x */
7112        "unexpected error %d\n", GetLastError());
7113
7114     SetLastError(0xdeadbeef);
7115     ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
7116     ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
7117        GetLastError() == 0xdeadbeef, /* Win9x */
7118        "unexpected error %d\n", GetLastError());
7119
7120     if (!pSetWinEventHook || !pUnhookWinEvent) return;
7121
7122     /* even process local incontext hooks require hmodule */
7123     SetLastError(0xdeadbeef);
7124     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
7125         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
7126     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
7127     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
7128        GetLastError() == 0xdeadbeef, /* Win9x */
7129        "unexpected error %d\n", GetLastError());
7130
7131     /* even thread local incontext hooks require hmodule */
7132     SetLastError(0xdeadbeef);
7133     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
7134         0, win_event_proc, GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
7135     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
7136     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
7137        GetLastError() == 0xdeadbeef, /* Win9x */
7138        "unexpected error %d\n", GetLastError());
7139
7140     if (0)
7141     {
7142     /* these 3 tests don't pass under Win9x */
7143     SetLastError(0xdeadbeef);
7144     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(1, 0,
7145         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
7146     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
7147     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
7148
7149     SetLastError(0xdeadbeef);
7150     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(-1, 1,
7151         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
7152     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
7153     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
7154
7155     SetLastError(0xdeadbeef);
7156     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
7157         0, win_event_proc, 0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
7158     ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
7159     ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
7160     }
7161
7162     SetLastError(0xdeadbeef);
7163     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(0, 0,
7164         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
7165     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
7166     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
7167     ret = pUnhookWinEvent(hwinevent_hook);
7168     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
7169
7170 todo_wine {
7171     /* This call succeeds under win2k SP4, but fails under Wine.
7172        Does win2k test/use passed process id? */
7173     SetLastError(0xdeadbeef);
7174     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
7175         0, win_event_proc, 0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
7176     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
7177     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
7178     ret = pUnhookWinEvent(hwinevent_hook);
7179     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
7180 }
7181
7182     SetLastError(0xdeadbeef);
7183     ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
7184     ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
7185         GetLastError() == 0xdeadbeef, /* Win9x */
7186         "unexpected error %d\n", GetLastError());
7187 }
7188
7189 static const struct message ScrollWindowPaint1[] = {
7190     { WM_PAINT, sent },
7191     { WM_ERASEBKGND, sent|beginpaint },
7192     { 0 }
7193 };
7194
7195 static const struct message ScrollWindowPaint2[] = {
7196     { WM_PAINT, sent },
7197     { 0 }
7198 };
7199
7200 static void test_scrollwindowex(void)
7201 {
7202     HWND hwnd, hchild;
7203     RECT rect={0,0,130,130};
7204     MSG msg;
7205
7206     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
7207             WS_VISIBLE|WS_OVERLAPPEDWINDOW,
7208             100, 100, 200, 200, 0, 0, 0, NULL);
7209     ok (hwnd != 0, "Failed to create overlapped window\n");
7210     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", 
7211             WS_VISIBLE|WS_CAPTION|WS_CHILD,
7212             10, 10, 150, 150, hwnd, 0, 0, NULL);
7213     ok (hchild != 0, "Failed to create child\n");
7214     UpdateWindow(hwnd);
7215     flush_events();
7216     flush_sequence();
7217
7218     /* scroll without the child window */
7219     trace("start scroll\n");
7220     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
7221             SW_ERASE|SW_INVALIDATE);
7222     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
7223     trace("end scroll\n");
7224     flush_sequence();
7225     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
7226     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
7227     flush_events();
7228     flush_sequence();
7229
7230     /* Now without the SW_ERASE flag */
7231     trace("start scroll\n");
7232     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
7233     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
7234     trace("end scroll\n");
7235     flush_sequence();
7236     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
7237     ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", 0);
7238     flush_events();
7239     flush_sequence();
7240
7241     /* now scroll the child window as well */
7242     trace("start scroll\n");
7243     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
7244             SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
7245     todo_wine { /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
7246                 /* windows sometimes a WM_MOVE */
7247         ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
7248     }
7249     trace("end scroll\n");
7250     flush_sequence();
7251     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
7252     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
7253     flush_events();
7254     flush_sequence();
7255
7256     /* now scroll with ScrollWindow() */
7257     trace("start scroll with ScrollWindow\n");
7258     ScrollWindow( hwnd, 5, 5, NULL, NULL);
7259     trace("end scroll\n");
7260     flush_sequence();
7261     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
7262     ok_sequence(ScrollWindowPaint1, "ScrollWindow", 0);
7263
7264     ok(DestroyWindow(hchild), "failed to destroy window\n");
7265     ok(DestroyWindow(hwnd), "failed to destroy window\n");
7266     flush_sequence();
7267 }
7268
7269 static const struct message destroy_window_with_children[] = {
7270     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
7271     { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
7272     { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
7273     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
7274     { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
7275     { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
7276     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
7277     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
7278     { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
7279     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
7280     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
7281     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
7282     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
7283     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
7284     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
7285     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
7286     { 0 }
7287 };
7288
7289 static void test_DestroyWindow(void)
7290 {
7291     BOOL ret;
7292     HWND parent, child1, child2, child3, child4, test;
7293     UINT child_id = WND_CHILD_ID + 1;
7294
7295     parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
7296                              100, 100, 200, 200, 0, 0, 0, NULL);
7297     assert(parent != 0);
7298     child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
7299                              0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
7300     assert(child1 != 0);
7301     child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
7302                              0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
7303     assert(child2 != 0);
7304     child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
7305                              0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
7306     assert(child3 != 0);
7307     child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
7308                              0, 0, 50, 50, parent, 0, 0, NULL);
7309     assert(child4 != 0);
7310
7311     /* test owner/parent of child2 */
7312     test = GetParent(child2);
7313     ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
7314     ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
7315     if(pGetAncestor) {
7316         test = pGetAncestor(child2, GA_PARENT);
7317         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
7318     }
7319     test = GetWindow(child2, GW_OWNER);
7320     ok(!test, "wrong owner %p\n", test);
7321
7322     test = SetParent(child2, parent);
7323     ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
7324
7325     /* test owner/parent of the parent */
7326     test = GetParent(parent);
7327     ok(!test, "wrong parent %p\n", test);
7328 todo_wine {
7329     ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
7330 }
7331     if(pGetAncestor) {
7332         test = pGetAncestor(parent, GA_PARENT);
7333         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
7334     }
7335     test = GetWindow(parent, GW_OWNER);
7336     ok(!test, "wrong owner %p\n", test);
7337
7338     /* test owner/parent of child1 */
7339     test = GetParent(child1);
7340     ok(test == parent, "wrong parent %p\n", test);
7341     ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
7342     if(pGetAncestor) {
7343         test = pGetAncestor(child1, GA_PARENT);
7344         ok(test == parent, "wrong parent %p\n", test);
7345     }
7346     test = GetWindow(child1, GW_OWNER);
7347     ok(!test, "wrong owner %p\n", test);
7348
7349     /* test owner/parent of child2 */
7350     test = GetParent(child2);
7351     ok(test == parent, "wrong parent %p\n", test);
7352     ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
7353     if(pGetAncestor) {
7354         test = pGetAncestor(child2, GA_PARENT);
7355         ok(test == parent, "wrong parent %p\n", test);
7356     }
7357     test = GetWindow(child2, GW_OWNER);
7358     ok(!test, "wrong owner %p\n", test);
7359
7360     /* test owner/parent of child3 */
7361     test = GetParent(child3);
7362     ok(test == child1, "wrong parent %p\n", test);
7363     ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
7364     if(pGetAncestor) {
7365         test = pGetAncestor(child3, GA_PARENT);
7366         ok(test == child1, "wrong parent %p\n", test);
7367     }
7368     test = GetWindow(child3, GW_OWNER);
7369     ok(!test, "wrong owner %p\n", test);
7370
7371     /* test owner/parent of child4 */
7372     test = GetParent(child4);
7373     ok(test == parent, "wrong parent %p\n", test);
7374     ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
7375     if(pGetAncestor) {
7376         test = pGetAncestor(child4, GA_PARENT);
7377         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
7378     }
7379     test = GetWindow(child4, GW_OWNER);
7380     ok(test == parent, "wrong owner %p\n", test);
7381
7382     flush_sequence();
7383
7384     trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
7385            parent, child1, child2, child3, child4);
7386
7387     SetCapture(child4);
7388     test = GetCapture();
7389     ok(test == child4, "wrong capture window %p\n", test);
7390
7391     test_DestroyWindow_flag = TRUE;
7392     ret = DestroyWindow(parent);
7393     ok( ret, "DestroyWindow() error %d\n", GetLastError());
7394     test_DestroyWindow_flag = FALSE;
7395     ok_sequence(destroy_window_with_children, "destroy window with children", 0);
7396
7397     ok(!IsWindow(parent), "parent still exists\n");
7398     ok(!IsWindow(child1), "child1 still exists\n");
7399     ok(!IsWindow(child2), "child2 still exists\n");
7400     ok(!IsWindow(child3), "child3 still exists\n");
7401     ok(!IsWindow(child4), "child4 still exists\n");
7402
7403     test = GetCapture();
7404     ok(!test, "wrong capture window %p\n", test);
7405 }
7406
7407
7408 static const struct message WmDispatchPaint[] = {
7409     { WM_NCPAINT, sent },
7410     { WM_GETTEXT, sent|defwinproc|optional },
7411     { WM_GETTEXT, sent|defwinproc|optional },
7412     { WM_ERASEBKGND, sent },
7413     { 0 }
7414 };
7415
7416 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7417 {
7418     if (message == WM_PAINT) return 0;
7419     return MsgCheckProcA( hwnd, message, wParam, lParam );
7420 }
7421
7422 static void test_DispatchMessage(void)
7423 {
7424     RECT rect;
7425     MSG msg;
7426     int count;
7427     HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
7428                                100, 100, 200, 200, 0, 0, 0, NULL);
7429     ShowWindow( hwnd, SW_SHOW );
7430     UpdateWindow( hwnd );
7431     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
7432     flush_sequence();
7433     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
7434
7435     SetRect( &rect, -5, -5, 5, 5 );
7436     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
7437     count = 0;
7438     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
7439     {
7440         if (msg.message != WM_PAINT) DispatchMessage( &msg );
7441         else
7442         {
7443             flush_sequence();
7444             DispatchMessage( &msg );
7445             /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
7446             if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
7447             else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
7448             if (++count > 10) break;
7449         }
7450     }
7451     ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
7452
7453     trace("now without DispatchMessage\n");
7454     flush_sequence();
7455     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
7456     count = 0;
7457     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
7458     {
7459         if (msg.message != WM_PAINT) DispatchMessage( &msg );
7460         else
7461         {
7462             HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
7463             flush_sequence();
7464             /* this will send WM_NCCPAINT just like DispatchMessage does */
7465             GetUpdateRgn( hwnd, hrgn, TRUE );
7466             ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
7467             DeleteObject( hrgn );
7468             GetClientRect( hwnd, &rect );
7469             ValidateRect( hwnd, &rect );  /* this will stop WM_PAINTs */
7470             ok( !count, "Got multiple WM_PAINTs\n" );
7471             if (++count > 10) break;
7472         }
7473     }
7474     DestroyWindow(hwnd);
7475 }
7476
7477
7478 static const struct message WmUser[] = {
7479     { WM_USER, sent },
7480     { 0 }
7481 };
7482
7483 struct sendmsg_info
7484 {
7485     HWND  hwnd;
7486     DWORD timeout;
7487     DWORD ret;
7488 };
7489
7490 static DWORD CALLBACK send_msg_thread( LPVOID arg )
7491 {
7492     struct sendmsg_info *info = arg;
7493     info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
7494     if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT, "unexpected error %d\n", GetLastError());
7495     return 0;
7496 }
7497
7498 static void wait_for_thread( HANDLE thread )
7499 {
7500     while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
7501     {
7502         MSG msg;
7503         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage(&msg);
7504     }
7505 }
7506
7507 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7508 {
7509     if (message == WM_USER) Sleep(200);
7510     return MsgCheckProcA( hwnd, message, wParam, lParam );
7511 }
7512
7513 static void test_SendMessageTimeout(void)
7514 {
7515     MSG msg;
7516     HANDLE thread;
7517     struct sendmsg_info info;
7518     DWORD tid;
7519
7520     info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
7521                                100, 100, 200, 200, 0, 0, 0, NULL);
7522     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
7523     flush_sequence();
7524
7525     info.timeout = 1000;
7526     info.ret = 0xdeadbeef;
7527     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
7528     wait_for_thread( thread );
7529     CloseHandle( thread );
7530     ok( info.ret == 1, "SendMessageTimeout failed\n" );
7531     ok_sequence( WmUser, "WmUser", FALSE );
7532
7533     info.timeout = 1;
7534     info.ret = 0xdeadbeef;
7535     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
7536     Sleep(100);  /* SendMessageTimeout should timeout here */
7537     wait_for_thread( thread );
7538     CloseHandle( thread );
7539     ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
7540     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
7541
7542     /* 0 means infinite timeout */
7543     info.timeout = 0;
7544     info.ret = 0xdeadbeef;
7545     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
7546     Sleep(100);
7547     wait_for_thread( thread );
7548     CloseHandle( thread );
7549     ok( info.ret == 1, "SendMessageTimeout failed\n" );
7550     ok_sequence( WmUser, "WmUser", FALSE );
7551
7552     /* timeout is treated as signed despite the prototype */
7553     info.timeout = 0x7fffffff;
7554     info.ret = 0xdeadbeef;
7555     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
7556     Sleep(100);
7557     wait_for_thread( thread );
7558     CloseHandle( thread );
7559     ok( info.ret == 1, "SendMessageTimeout failed\n" );
7560     ok_sequence( WmUser, "WmUser", FALSE );
7561
7562     info.timeout = 0x80000000;
7563     info.ret = 0xdeadbeef;
7564     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
7565     Sleep(100);
7566     wait_for_thread( thread );
7567     CloseHandle( thread );
7568     ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
7569     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
7570
7571     /* now check for timeout during message processing */
7572     SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
7573     info.timeout = 100;
7574     info.ret = 0xdeadbeef;
7575     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
7576     wait_for_thread( thread );
7577     CloseHandle( thread );
7578     /* we should timeout but still get the message */
7579     ok( info.ret == 0, "SendMessageTimeout failed\n" );
7580     ok_sequence( WmUser, "WmUser", FALSE );
7581
7582     DestroyWindow( info.hwnd );
7583 }
7584
7585
7586 /****************** edit message test *************************/
7587 #define ID_EDIT 0x1234
7588 static const struct message sl_edit_setfocus[] =
7589 {
7590     { HCBT_SETFOCUS, hook },
7591     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
7592     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
7593     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7594     { WM_SETFOCUS, sent|wparam, 0 },
7595     { WM_CTLCOLOREDIT, sent|parent },
7596     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7597     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7598     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
7599     { 0 }
7600 };
7601 static const struct message ml_edit_setfocus[] =
7602 {
7603     { HCBT_SETFOCUS, hook },
7604     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
7605     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
7606     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7607     { WM_SETFOCUS, sent|wparam, 0 },
7608     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7609     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7610     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7611     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
7612     { 0 }
7613 };
7614 static const struct message sl_edit_killfocus[] =
7615 {
7616     { HCBT_SETFOCUS, hook },
7617     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7618     { WM_KILLFOCUS, sent|wparam, 0 },
7619     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7620     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7621     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
7622     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
7623     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
7624     { 0 }
7625 };
7626 static const struct message sl_edit_lbutton_dblclk[] =
7627 {
7628     { WM_LBUTTONDBLCLK, sent },
7629     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
7630     { 0 }
7631 };
7632 static const struct message sl_edit_lbutton_down[] =
7633 {
7634     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
7635     { HCBT_SETFOCUS, hook },
7636     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
7637     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
7638     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7639     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
7640     { WM_CTLCOLOREDIT, sent|parent },
7641     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7642     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7643     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7644     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
7645     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
7646     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7647     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7648     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7649     { 0 }
7650 };
7651 static const struct message ml_edit_lbutton_down[] =
7652 {
7653     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
7654     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
7655     { HCBT_SETFOCUS, hook },
7656     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
7657     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
7658     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7659     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
7660     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7661     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7662     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
7663     { 0 }
7664 };
7665 static const struct message sl_edit_lbutton_up[] =
7666 {
7667     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
7668     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7669     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
7670     { WM_CAPTURECHANGED, sent|defwinproc },
7671     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7672     { 0 }
7673 };
7674 static const struct message ml_edit_lbutton_up[] =
7675 {
7676     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
7677     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
7678     { WM_CAPTURECHANGED, sent|defwinproc },
7679     { 0 }
7680 };
7681
7682 static WNDPROC old_edit_proc;
7683
7684 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7685 {
7686     static long defwndproc_counter = 0;
7687     LRESULT ret;
7688     struct message msg;
7689
7690     trace("edit: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
7691
7692     /* explicitly ignore WM_GETICON message */
7693     if (message == WM_GETICON) return 0;
7694
7695     msg.message = message;
7696     msg.flags = sent|wparam|lparam;
7697     if (defwndproc_counter) msg.flags |= defwinproc;
7698     msg.wParam = wParam;
7699     msg.lParam = lParam;
7700     add_message(&msg);
7701
7702     defwndproc_counter++;
7703     ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
7704     defwndproc_counter--;
7705
7706     return ret;
7707 }
7708
7709 static void subclass_edit(void)
7710 {
7711     WNDCLASSA cls;
7712
7713     if (!GetClassInfoA(0, "edit", &cls)) assert(0);
7714
7715     old_edit_proc = cls.lpfnWndProc;
7716
7717     cls.hInstance = GetModuleHandle(0);
7718     cls.lpfnWndProc = edit_hook_proc;
7719     cls.lpszClassName = "my_edit_class";
7720     UnregisterClass(cls.lpszClassName, cls.hInstance);
7721     if (!RegisterClassA(&cls)) assert(0);
7722 }
7723
7724 static void test_edit_messages(void)
7725 {
7726     HWND hwnd, parent;
7727     DWORD dlg_code;
7728
7729     subclass_edit();
7730     log_all_parent_messages++;
7731
7732     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7733                              100, 100, 200, 200, 0, 0, 0, NULL);
7734     ok (parent != 0, "Failed to create parent window\n");
7735
7736     /* test single line edit */
7737     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
7738                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
7739     ok(hwnd != 0, "Failed to create edit window\n");
7740
7741     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
7742     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
7743
7744     ShowWindow(hwnd, SW_SHOW);
7745     UpdateWindow(hwnd);
7746     SetFocus(0);
7747     flush_sequence();
7748
7749     SetFocus(hwnd);
7750     ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
7751
7752     SetFocus(0);
7753     ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
7754
7755     SetFocus(0);
7756     ReleaseCapture();
7757     flush_sequence();
7758
7759     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
7760     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
7761
7762     SetFocus(0);
7763     ReleaseCapture();
7764     flush_sequence();
7765
7766     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
7767     ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
7768
7769     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
7770     ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
7771
7772     DestroyWindow(hwnd);
7773
7774     /* test multiline edit */
7775     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
7776                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
7777     ok(hwnd != 0, "Failed to create edit window\n");
7778
7779     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
7780     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
7781        "wrong dlg_code %08x\n", dlg_code);
7782
7783     ShowWindow(hwnd, SW_SHOW);
7784     UpdateWindow(hwnd);
7785     SetFocus(0);
7786     flush_sequence();
7787
7788     SetFocus(hwnd);
7789     ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
7790
7791     SetFocus(0);
7792     ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
7793
7794     SetFocus(0);
7795     ReleaseCapture();
7796     flush_sequence();
7797
7798     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
7799     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
7800
7801     SetFocus(0);
7802     ReleaseCapture();
7803     flush_sequence();
7804
7805     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
7806     ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
7807
7808     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
7809     ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
7810
7811     DestroyWindow(hwnd);
7812     DestroyWindow(parent);
7813
7814     log_all_parent_messages--;
7815 }
7816
7817 /**************************** End of Edit test ******************************/
7818
7819 static const struct message WmKeyDownSkippedSeq[] =
7820 {
7821     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
7822     { 0 }
7823 };
7824 static const struct message WmKeyUpSkippedSeq[] =
7825 {
7826     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
7827     { 0 }
7828 };
7829
7830 #define EV_START_STOP 0
7831 #define EV_SENDMSG 1
7832 #define EV_ACK 2
7833
7834 struct peekmsg_info
7835 {
7836     HWND  hwnd;
7837     HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
7838 };
7839
7840 static DWORD CALLBACK send_msg_thread_2(void *param)
7841 {
7842     DWORD ret;
7843     struct peekmsg_info *info = param;
7844
7845     trace("thread: waiting for start\n");
7846     WaitForSingleObject(info->hevent[EV_START_STOP], INFINITE);
7847     trace("thread: looping\n");
7848
7849     while (1)
7850     {
7851         ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
7852
7853         switch (ret)
7854         {
7855         case WAIT_OBJECT_0 + EV_START_STOP:
7856             trace("thread: exiting\n");
7857             return 0;
7858
7859         case WAIT_OBJECT_0 + EV_SENDMSG:
7860             trace("thread: sending message\n");
7861             SendNotifyMessageA(info->hwnd, WM_USER, 0, 0);
7862             SetEvent(info->hevent[EV_ACK]);
7863             break;
7864
7865         default:
7866             trace("unexpected return: %04x\n", ret);
7867             assert(0);
7868             break;
7869         }
7870     }
7871     return 0;
7872 }
7873
7874 static void test_PeekMessage(void)
7875 {
7876     MSG msg;
7877     HANDLE hthread;
7878     DWORD tid, qstatus;
7879     UINT qs_all_input = QS_ALLINPUT;
7880     UINT qs_input = QS_INPUT;
7881     BOOL ret;
7882     struct peekmsg_info info;
7883
7884     info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
7885                               100, 100, 200, 200, 0, 0, 0, NULL);
7886     assert(info.hwnd);
7887     ShowWindow(info.hwnd, SW_SHOW);
7888     UpdateWindow(info.hwnd);
7889     SetFocus(info.hwnd);
7890
7891     info.hevent[EV_START_STOP] = CreateEventA(NULL, 0, 0, NULL);
7892     info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
7893     info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
7894
7895     hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
7896     Sleep(100);
7897
7898     trace("signalling to start looping\n");
7899     SetEvent(info.hevent[EV_START_STOP]);
7900
7901     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7902     flush_sequence();
7903
7904     SetLastError(0xdeadbeef);
7905     qstatus = GetQueueStatus(qs_all_input);
7906     if (GetLastError() == ERROR_INVALID_FLAGS)
7907     {
7908         trace("QS_RAWINPUT not supported on this platform\n");
7909         qs_all_input &= ~QS_RAWINPUT;
7910         qs_input &= ~QS_RAWINPUT;
7911     }
7912     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
7913
7914     trace("signalling to send message\n");
7915     SetEvent(info.hevent[EV_SENDMSG]);
7916     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
7917
7918     /* pass invalid QS_xxxx flags */
7919     SetLastError(0xdeadbeef);
7920     qstatus = GetQueueStatus(0xffffffff);
7921     ok(qstatus == 0, "GetQueueStatus should fail: %08x\n", qstatus);
7922     ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
7923
7924     qstatus = GetQueueStatus(qs_all_input);
7925     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
7926        "wrong qstatus %08x\n", qstatus);
7927
7928     msg.message = 0;
7929     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
7930     ok(!ret,
7931        "PeekMessageA should have returned FALSE instead of msg %04x\n",
7932         msg.message);
7933     ok_sequence(WmUser, "WmUser", FALSE);
7934
7935     qstatus = GetQueueStatus(qs_all_input);
7936     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
7937
7938     keybd_event('N', 0, 0, 0);
7939     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7940     qstatus = GetQueueStatus(qs_all_input);
7941     ok(qstatus == MAKELONG(QS_KEY, QS_KEY),
7942        "wrong qstatus %08x\n", qstatus);
7943
7944     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
7945     qstatus = GetQueueStatus(qs_all_input);
7946     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
7947        "wrong qstatus %08x\n", qstatus);
7948
7949     InvalidateRect(info.hwnd, NULL, FALSE);
7950     qstatus = GetQueueStatus(qs_all_input);
7951     ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
7952        "wrong qstatus %08x\n", qstatus);
7953
7954     trace("signalling to send message\n");
7955     SetEvent(info.hevent[EV_SENDMSG]);
7956     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
7957
7958     qstatus = GetQueueStatus(qs_all_input);
7959     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
7960        "wrong qstatus %08x\n", qstatus);
7961
7962     msg.message = 0;
7963     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
7964     ok(!ret,
7965        "PeekMessageA should have returned FALSE instead of msg %04x\n",
7966         msg.message);
7967     ok_sequence(WmUser, "WmUser", FALSE);
7968
7969     qstatus = GetQueueStatus(qs_all_input);
7970     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
7971        "wrong qstatus %08x\n", qstatus);
7972
7973     trace("signalling to send message\n");
7974     SetEvent(info.hevent[EV_SENDMSG]);
7975     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
7976
7977     qstatus = GetQueueStatus(qs_all_input);
7978     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
7979        "wrong qstatus %08x\n", qstatus);
7980
7981     msg.message = 0;
7982     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
7983     ok(!ret,
7984        "PeekMessageA should have returned FALSE instead of msg %04x\n",
7985         msg.message);
7986     ok_sequence(WmUser, "WmUser", FALSE);
7987
7988     qstatus = GetQueueStatus(qs_all_input);
7989     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
7990        "wrong qstatus %08x\n", qstatus);
7991
7992     msg.message = 0;
7993     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
7994     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
7995        "got %d and %04x wParam %08x instead of TRUE and WM_CHAR wParam 'z'\n",
7996        ret, msg.message, msg.wParam);
7997     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
7998
7999     qstatus = GetQueueStatus(qs_all_input);
8000     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
8001        "wrong qstatus %08x\n", qstatus);
8002
8003     msg.message = 0;
8004     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
8005     ok(!ret,
8006        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8007         msg.message);
8008     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8009
8010     qstatus = GetQueueStatus(qs_all_input);
8011     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
8012        "wrong qstatus %08x\n", qstatus);
8013
8014     msg.message = 0;
8015     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
8016     ok(ret && msg.message == WM_PAINT,
8017        "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
8018     DispatchMessageA(&msg);
8019     ok_sequence(WmPaint, "WmPaint", FALSE);
8020
8021     qstatus = GetQueueStatus(qs_all_input);
8022     ok(qstatus == MAKELONG(0, QS_KEY),
8023        "wrong qstatus %08x\n", qstatus);
8024
8025     msg.message = 0;
8026     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
8027     ok(!ret,
8028        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8029         msg.message);
8030     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8031
8032     qstatus = GetQueueStatus(qs_all_input);
8033     ok(qstatus == MAKELONG(0, QS_KEY),
8034        "wrong qstatus %08x\n", qstatus);
8035
8036     trace("signalling to send message\n");
8037     SetEvent(info.hevent[EV_SENDMSG]);
8038     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8039
8040     qstatus = GetQueueStatus(qs_all_input);
8041     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
8042        "wrong qstatus %08x\n", qstatus);
8043
8044     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
8045
8046     qstatus = GetQueueStatus(qs_all_input);
8047     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
8048        "wrong qstatus %08x\n", qstatus);
8049
8050     msg.message = 0;
8051     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
8052     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
8053        "got %d and %04x wParam %08x instead of TRUE and WM_CHAR wParam 'z'\n",
8054        ret, msg.message, msg.wParam);
8055     ok_sequence(WmUser, "WmUser", FALSE);
8056
8057     qstatus = GetQueueStatus(qs_all_input);
8058     ok(qstatus == MAKELONG(0, QS_KEY),
8059        "wrong qstatus %08x\n", qstatus);
8060
8061     msg.message = 0;
8062     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
8063     ok(!ret,
8064        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8065         msg.message);
8066     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8067
8068     qstatus = GetQueueStatus(qs_all_input);
8069     ok(qstatus == MAKELONG(0, QS_KEY),
8070        "wrong qstatus %08x\n", qstatus);
8071
8072     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
8073
8074     qstatus = GetQueueStatus(qs_all_input);
8075     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
8076        "wrong qstatus %08x\n", qstatus);
8077
8078     trace("signalling to send message\n");
8079     SetEvent(info.hevent[EV_SENDMSG]);
8080     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8081
8082     qstatus = GetQueueStatus(qs_all_input);
8083     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
8084        "wrong qstatus %08x\n", qstatus);
8085
8086     msg.message = 0;
8087     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
8088     ok(!ret,
8089        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8090         msg.message);
8091     ok_sequence(WmUser, "WmUser", FALSE);
8092
8093     qstatus = GetQueueStatus(qs_all_input);
8094     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
8095        "wrong qstatus %08x\n", qstatus);
8096
8097     msg.message = 0;
8098     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
8099         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
8100     else /* workaround for a missing QS_RAWINPUT support */
8101         ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
8102     ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
8103        "got %d and %04x wParam %08x instead of TRUE and WM_KEYDOWN wParam 'N'\n",
8104        ret, msg.message, msg.wParam);
8105     ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
8106
8107     qstatus = GetQueueStatus(qs_all_input);
8108     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
8109        "wrong qstatus %08x\n", qstatus);
8110
8111     msg.message = 0;
8112     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
8113         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
8114     else /* workaround for a missing QS_RAWINPUT support */
8115         ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
8116     ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
8117        "got %d and %04x wParam %08x instead of TRUE and WM_KEYUP wParam 'N'\n",
8118        ret, msg.message, msg.wParam);
8119     ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
8120
8121     qstatus = GetQueueStatus(qs_all_input);
8122     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
8123        "wrong qstatus %08x\n", qstatus);
8124
8125     msg.message = 0;
8126     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
8127     ok(!ret,
8128        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8129         msg.message);
8130     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8131
8132     qstatus = GetQueueStatus(qs_all_input);
8133     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
8134        "wrong qstatus %08x\n", qstatus);
8135
8136     msg.message = 0;
8137     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8138     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
8139        "got %d and %04x wParam %08x instead of TRUE and WM_CHAR wParam 'z'\n",
8140        ret, msg.message, msg.wParam);
8141     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8142
8143     qstatus = GetQueueStatus(qs_all_input);
8144     ok(qstatus == 0,
8145        "wrong qstatus %08x\n", qstatus);
8146
8147     msg.message = 0;
8148     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8149     ok(!ret,
8150        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8151         msg.message);
8152     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8153
8154     qstatus = GetQueueStatus(qs_all_input);
8155     ok(qstatus == 0,
8156        "wrong qstatus %08x\n", qstatus);
8157
8158     /* test whether presence of the quit flag in the queue affects
8159      * the queue state
8160      */
8161     PostQuitMessage(0x1234abcd);
8162
8163     qstatus = GetQueueStatus(qs_all_input);
8164     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
8165        "wrong qstatus %08x\n", qstatus);
8166
8167     PostMessageA(info.hwnd, WM_USER, 0, 0);
8168
8169     qstatus = GetQueueStatus(qs_all_input);
8170     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
8171        "wrong qstatus %08x\n", qstatus);
8172
8173     msg.message = 0;
8174     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8175     ok(ret && msg.message == WM_USER,
8176        "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
8177     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8178
8179     qstatus = GetQueueStatus(qs_all_input);
8180     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
8181        "wrong qstatus %08x\n", qstatus);
8182
8183     msg.message = 0;
8184     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8185     ok(ret && msg.message == WM_QUIT,
8186        "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
8187     ok(msg.wParam == 0x1234abcd, "got wParam %08x instead of 0x1234abcd\n", msg.wParam);
8188     ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
8189     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8190
8191     qstatus = GetQueueStatus(qs_all_input);
8192 todo_wine {
8193     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
8194        "wrong qstatus %08x\n", qstatus);
8195 }
8196
8197     msg.message = 0;
8198     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8199     ok(!ret,
8200        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8201         msg.message);
8202     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8203
8204     qstatus = GetQueueStatus(qs_all_input);
8205     ok(qstatus == 0,
8206        "wrong qstatus %08x\n", qstatus);
8207
8208     trace("signalling to exit\n");
8209     SetEvent(info.hevent[EV_START_STOP]);
8210
8211     WaitForSingleObject(hthread, INFINITE);
8212
8213     CloseHandle(hthread);
8214     CloseHandle(info.hevent[0]);
8215     CloseHandle(info.hevent[1]);
8216     CloseHandle(info.hevent[2]);
8217
8218     DestroyWindow(info.hwnd);
8219 }
8220
8221
8222 static void test_quit_message(void)
8223 {
8224     MSG msg;
8225     BOOL ret;
8226
8227     /* test using PostQuitMessage */
8228     PostQuitMessage(0xbeef);
8229
8230     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
8231     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
8232     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
8233     ok(msg.wParam == 0xbeef, "wParam was 0x%x instead of 0xbeef\n", msg.wParam);
8234
8235     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
8236     ok(ret, "PostMessage failed with error %d\n", GetLastError());
8237
8238     ret = GetMessage(&msg, NULL, 0, 0);
8239     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
8240     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
8241
8242     /* note: WM_QUIT message received after WM_USER message */
8243     ret = GetMessage(&msg, NULL, 0, 0);
8244     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
8245     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
8246     ok(msg.wParam == 0xbeef, "wParam was 0x%x instead of 0xbeef\n", msg.wParam);
8247
8248     ret = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
8249     ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
8250
8251     /* now test with PostThreadMessage - different behaviour! */
8252     PostThreadMessage(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
8253
8254     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
8255     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
8256     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
8257     ok(msg.wParam == 0xdead, "wParam was 0x%x instead of 0xdead\n", msg.wParam);
8258
8259     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
8260     ok(ret, "PostMessage failed with error %d\n", GetLastError());
8261
8262     /* note: we receive the WM_QUIT message first this time */
8263     ret = GetMessage(&msg, NULL, 0, 0);
8264     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
8265     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
8266     ok(msg.wParam == 0xdead, "wParam was 0x%x instead of 0xdead\n", msg.wParam);
8267
8268     ret = GetMessage(&msg, NULL, 0, 0);
8269     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
8270     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
8271 }
8272
8273 static const struct message WmMouseHoverSeq[] = {
8274     { WM_TIMER, sent|optional }, /* XP sends it */
8275     { WM_SYSTIMER, sent },
8276     { WM_MOUSEHOVER, sent|wparam, 0 },
8277     { 0 }
8278 };
8279
8280 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
8281 {
8282     MSG msg;
8283     DWORD start_ticks, end_ticks;
8284
8285     start_ticks = GetTickCount();
8286     /* add some deviation (5%) to cover not expected delays */
8287     start_ticks += timeout / 20;
8288
8289     do
8290     {
8291         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
8292         {
8293             /* Timer proc messages are not dispatched to the window proc,
8294              * and therefore not logged.
8295              */
8296             if (msg.message == WM_TIMER || msg.message == WM_SYSTIMER)
8297             {
8298                 struct message s_msg;
8299
8300                 s_msg.message = msg.message;
8301                 s_msg.flags = sent|wparam|lparam;
8302                 s_msg.wParam = msg.wParam;
8303                 s_msg.lParam = msg.lParam;
8304                 add_message(&s_msg);
8305             }
8306             DispatchMessage(&msg);
8307         }
8308
8309         end_ticks = GetTickCount();
8310
8311         /* inject WM_MOUSEMOVE to see how it changes tracking */
8312         if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
8313         {
8314             mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8315             mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8316
8317             inject_mouse_move = FALSE;
8318         }
8319     } while (start_ticks + timeout >= end_ticks);
8320 }
8321
8322 static void test_TrackMouseEvent(void)
8323 {
8324     MSG msg;
8325     TRACKMOUSEEVENT tme;
8326     BOOL ret;
8327     HWND hwnd, hchild;
8328     RECT rc_parent, rc_child;
8329     UINT default_hover_time, hover_width = 0, hover_height = 0;
8330
8331 #define track_hover(track_hwnd, track_hover_time) \
8332     tme.cbSize = sizeof(tme); \
8333     tme.dwFlags = TME_HOVER; \
8334     tme.hwndTrack = track_hwnd; \
8335     tme.dwHoverTime = track_hover_time; \
8336     SetLastError(0xdeadbeef); \
8337     ret = TrackMouseEvent(&tme); \
8338     ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
8339
8340 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
8341     tme.cbSize = sizeof(tme); \
8342     tme.dwFlags = TME_QUERY; \
8343     tme.hwndTrack = (HWND)0xdeadbeef; \
8344     tme.dwHoverTime = 0xdeadbeef; \
8345     SetLastError(0xdeadbeef); \
8346     ret = TrackMouseEvent(&tme); \
8347     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
8348     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
8349     ok(tme.dwFlags == (expected_track_flags), \
8350        "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
8351     ok(tme.hwndTrack == (expected_track_hwnd), \
8352        "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
8353     ok(tme.dwHoverTime == (expected_hover_time), \
8354        "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
8355
8356 #define track_hover_cancel(track_hwnd) \
8357     tme.cbSize = sizeof(tme); \
8358     tme.dwFlags = TME_HOVER | TME_CANCEL; \
8359     tme.hwndTrack = track_hwnd; \
8360     tme.dwHoverTime = 0xdeadbeef; \
8361     SetLastError(0xdeadbeef); \
8362     ret = TrackMouseEvent(&tme); \
8363     ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
8364
8365     default_hover_time = 0xdeadbeef;
8366     SetLastError(0xdeadbeef);
8367     ret = SystemParametersInfo(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
8368     ok(ret, "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
8369     if (!ret) default_hover_time = 400;
8370     trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
8371
8372     SetLastError(0xdeadbeef);
8373     ret = SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
8374     ok(ret, "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
8375     if (!ret) hover_width = 4;
8376     SetLastError(0xdeadbeef);
8377     ret = SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
8378     ok(ret, "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
8379     if (!ret) hover_height = 4;
8380     trace("hover rect is %u x %d\n", hover_width, hover_height);
8381
8382     hwnd = CreateWindowEx(0, "TestWindowClass", NULL,
8383                           WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8384                           CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
8385                           NULL, NULL, 0);
8386     assert(hwnd);
8387
8388     hchild = CreateWindowEx(0, "TestWindowClass", NULL,
8389                           WS_CHILD | WS_BORDER | WS_VISIBLE,
8390                           50, 50, 200, 200, hwnd,
8391                           NULL, NULL, 0);
8392     assert(hchild);
8393
8394     flush_events();
8395     flush_sequence();
8396
8397     tme.cbSize = 0;
8398     tme.dwFlags = TME_QUERY;
8399     tme.hwndTrack = (HWND)0xdeadbeef;
8400     tme.dwHoverTime = 0xdeadbeef;
8401     SetLastError(0xdeadbeef);
8402     ret = TrackMouseEvent(&tme);
8403     ok(!ret, "TrackMouseEvent should fail\n");
8404     ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
8405
8406     tme.cbSize = sizeof(tme);
8407     tme.dwFlags = TME_HOVER;
8408     tme.hwndTrack = (HWND)0xdeadbeef;
8409     tme.dwHoverTime = 0xdeadbeef;
8410     SetLastError(0xdeadbeef);
8411     ret = TrackMouseEvent(&tme);
8412     ok(!ret, "TrackMouseEvent should fail\n");
8413     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "not expected error %d\n", GetLastError());
8414
8415     tme.cbSize = sizeof(tme);
8416     tme.dwFlags = TME_HOVER | TME_CANCEL;
8417     tme.hwndTrack = (HWND)0xdeadbeef;
8418     tme.dwHoverTime = 0xdeadbeef;
8419     SetLastError(0xdeadbeef);
8420     ret = TrackMouseEvent(&tme);
8421     ok(!ret, "TrackMouseEvent should fail\n");
8422     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "not expected error %d\n", GetLastError());
8423
8424     GetWindowRect(hwnd, &rc_parent);
8425     GetWindowRect(hchild, &rc_child);
8426     SetCursorPos(rc_child.left - 10, rc_child.top - 10);
8427
8428     /* Process messages so that the system updates its internal current
8429      * window and hittest, otherwise TrackMouseEvent calls don't have any
8430      * effect.
8431      */
8432     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
8433     flush_sequence();
8434
8435     track_query(0, NULL, 0);
8436     track_hover(hchild, 0);
8437     track_query(0, NULL, 0);
8438
8439     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
8440     flush_sequence();
8441
8442     track_hover(hwnd, 0);
8443     track_query(TME_HOVER, hwnd, default_hover_time);
8444
8445     pump_msg_loop_timeout(default_hover_time, FALSE);
8446     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
8447
8448     track_query(0, NULL, 0);
8449
8450     track_hover(hwnd, HOVER_DEFAULT);
8451     track_query(TME_HOVER, hwnd, default_hover_time);
8452
8453     Sleep(default_hover_time / 2);
8454     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8455     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8456
8457     track_query(TME_HOVER, hwnd, default_hover_time);
8458
8459     pump_msg_loop_timeout(default_hover_time / 2, FALSE);
8460     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
8461
8462     track_query(0, NULL, 0);
8463
8464     track_hover(hwnd, HOVER_DEFAULT);
8465     track_query(TME_HOVER, hwnd, default_hover_time);
8466
8467     pump_msg_loop_timeout(default_hover_time, TRUE);
8468     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
8469
8470     track_query(0, NULL, 0);
8471
8472     track_hover(hwnd, HOVER_DEFAULT);
8473     track_query(TME_HOVER, hwnd, default_hover_time);
8474     track_hover_cancel(hwnd);
8475
8476     DestroyWindow(hwnd);
8477
8478 #undef track_hover
8479 #undef track_query
8480 #undef track_hover_cancel
8481 }
8482
8483
8484 static const struct message WmSetWindowRgn[] = {
8485     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
8486     { WM_NCCALCSIZE, sent|wparam, 1 },
8487     { WM_NCPAINT, sent }, /* wparam != 1 */
8488     { WM_GETTEXT, sent|defwinproc|optional },
8489     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
8490     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
8491     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
8492     { 0 }
8493 };
8494
8495 static const struct message WmSetWindowRgn_no_redraw[] = {
8496     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
8497     { WM_NCCALCSIZE, sent|wparam, 1 },
8498     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
8499     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
8500     { 0 }
8501 };
8502
8503 static const struct message WmSetWindowRgn_clear[] = {
8504     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE }, /* some versions of 2000/XP also has SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE in wparam */
8505     { WM_NCCALCSIZE, sent|wparam, 1 },
8506     { WM_NCPAINT, sent }, /* wparam != 1 */
8507     { WM_GETTEXT, sent|defwinproc|optional },
8508     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
8509     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
8510     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
8511     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
8512     { WM_GETTEXT, sent|defwinproc|optional },
8513     { WM_ERASEBKGND, sent|optional },
8514     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
8515     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
8516     { 0 }
8517 };
8518
8519 static void test_SetWindowRgn(void)
8520 {
8521     HRGN hrgn;
8522     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
8523                                 100, 100, 200, 200, 0, 0, 0, NULL);
8524     ok( hwnd != 0, "Failed to create overlapped window\n" );
8525
8526     ShowWindow( hwnd, SW_SHOW );
8527     UpdateWindow( hwnd );
8528     flush_events();
8529     flush_sequence();
8530
8531     trace("testing SetWindowRgn\n");
8532     hrgn = CreateRectRgn( 0, 0, 150, 150 );
8533     SetWindowRgn( hwnd, hrgn, TRUE );
8534     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
8535
8536     hrgn = CreateRectRgn( 30, 30, 160, 160 );
8537     SetWindowRgn( hwnd, hrgn, FALSE );
8538     ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
8539
8540     hrgn = CreateRectRgn( 0, 0, 180, 180 );
8541     SetWindowRgn( hwnd, hrgn, TRUE );
8542     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
8543
8544     SetWindowRgn( hwnd, 0, TRUE );
8545     ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
8546
8547     DestroyWindow( hwnd );
8548 }
8549
8550 /*************************** ShowWindow() test ******************************/
8551 static const struct message WmShowNormal[] = {
8552     { WM_SHOWWINDOW, sent|wparam, 1 },
8553     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
8554     { HCBT_ACTIVATE, hook },
8555     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
8556     { HCBT_SETFOCUS, hook },
8557     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
8558     { 0 }
8559 };
8560 static const struct message WmShow[] = {
8561     { WM_SHOWWINDOW, sent|wparam, 1 },
8562     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
8563     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
8564     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
8565     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
8566     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
8567     { 0 }
8568 };
8569 static const struct message WmShowNoActivate_1[] = {
8570     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
8571     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|0x8000 },
8572     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|0x8000 },
8573     { WM_MOVE, sent|defwinproc },
8574     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
8575     { 0 }
8576 };
8577 static const struct message WmShowNoActivate_2[] = {
8578     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
8579     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8580     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8581     { WM_MOVE, sent|defwinproc },
8582     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
8583     { HCBT_SETFOCUS, hook },
8584     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
8585     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
8586     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
8587     { 0 }
8588 };
8589 static const struct message WmShowNA_1[] = {
8590     { WM_SHOWWINDOW, sent|wparam, 1 },
8591     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
8592     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
8593     { 0 }
8594 };
8595 static const struct message WmShowNA_2[] = {
8596     { WM_SHOWWINDOW, sent|wparam, 1 },
8597     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
8598     { 0 }
8599 };
8600 static const struct message WmRestore_1[] = {
8601     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
8602     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8603     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
8604     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
8605     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
8606     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8607     { WM_MOVE, sent|defwinproc },
8608     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
8609     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
8610     { 0 }
8611 };
8612 static const struct message WmRestore_2[] = {
8613     { WM_SHOWWINDOW, sent|wparam, 1 },
8614     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
8615     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
8616     { 0 }
8617 };
8618 static const struct message WmRestore_3[] = {
8619     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
8620     { WM_GETMINMAXINFO, sent },
8621     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8622     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
8623     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
8624     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
8625     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8626     { WM_MOVE, sent|defwinproc },
8627     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
8628     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
8629     { 0 }
8630 };
8631 static const struct message WmRestore_4[] = {
8632     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
8633     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
8634     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|0x8000 },
8635     { WM_MOVE, sent|defwinproc },
8636     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
8637     { 0 }
8638 };
8639 static const struct message WmRestore_5[] = {
8640     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
8641     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
8642     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|0x8000 },
8643     { WM_MOVE, sent|defwinproc },
8644     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
8645     { 0 }
8646 };
8647 static const struct message WmHide_1[] = {
8648     { WM_SHOWWINDOW, sent|wparam, 0 },
8649     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
8650     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
8651     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
8652     { 0 }
8653 };
8654 static const struct message WmHide_2[] = {
8655     { WM_SHOWWINDOW, sent|wparam, 0 },
8656     { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
8657     { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
8658     { 0 }
8659 };
8660 static const struct message WmHide_3[] = {
8661     { WM_SHOWWINDOW, sent|wparam, 0 },
8662     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
8663     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
8664     { HCBT_SETFOCUS, hook },
8665     { 0 }
8666 };
8667 static const struct message WmShowMinimized_1[] = {
8668     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
8669     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8670     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
8671     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
8672     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8673     { WM_MOVE, sent|defwinproc },
8674     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
8675     { 0 }
8676 };
8677 static const struct message WmMinimize_1[] = {
8678     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
8679     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
8680     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8681     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8682     { WM_MOVE, sent|defwinproc },
8683     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
8684     { 0 }
8685 };
8686 static const struct message WmMinimize_2[] = {
8687     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
8688     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8689     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8690     { WM_MOVE, sent|defwinproc },
8691     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
8692     { 0 }
8693 };
8694 static const struct message WmMinimize_3[] = {
8695     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
8696     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8697     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8698     { WM_MOVE, sent|defwinproc },
8699     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
8700     { 0 }
8701 };
8702 static const struct message WmShowMinNoActivate[] = {
8703     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
8704     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
8705     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
8706     { 0 }
8707 };
8708 static const struct message WmMinMax_1[] = {
8709     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
8710     { 0 }
8711 };
8712 static const struct message WmMinMax_2[] = {
8713     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
8714     { 0 }
8715 };
8716 static const struct message WmMinMax_3[] = {
8717     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
8718     { 0 }
8719 };
8720 static const struct message WmMinMax_4[] = {
8721     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
8722     { 0 }
8723 };
8724 static const struct message WmShowMaximized_1[] = {
8725     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
8726     { WM_GETMINMAXINFO, sent },
8727     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8728     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
8729     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
8730     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
8731     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8732     { WM_MOVE, sent|defwinproc },
8733     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
8734     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
8735     { 0 }
8736 };
8737 static const struct message WmShowMaximized_2[] = {
8738     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
8739     { WM_GETMINMAXINFO, sent },
8740     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
8741     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
8742     { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
8743     { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
8744     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8745     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8746     { WM_MOVE, sent|defwinproc },
8747     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
8748     { HCBT_SETFOCUS, hook },
8749     { 0 }
8750 };
8751 static const struct message WmShowMaximized_3[] = {
8752     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
8753     { WM_GETMINMAXINFO, sent },
8754     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
8755     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|0x8000 },
8756     { WM_MOVE, sent|defwinproc },
8757     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
8758     { 0 }
8759 };
8760
8761 static void test_ShowWindow(void)
8762 {
8763     /* ShowWindow commands in random order */
8764     static const struct
8765     {
8766         INT cmd; /* ShowWindow command */
8767         LPARAM ret; /* ShowWindow return value */
8768         DWORD style; /* window style after the command */
8769         const struct message *msg; /* message sequence the command produces */
8770         BOOL todo_msg; /* message sequence doesn't match what Wine does */
8771     } sw[] =
8772     {
8773 /*  1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal, FALSE },
8774 /*  2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
8775 /*  3 */ { SW_HIDE, TRUE, 0, WmHide_1, FALSE },
8776 /*  4 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
8777 /*  5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1, FALSE },
8778 /*  6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1, FALSE },
8779 /*  7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1, FALSE },
8780 /*  8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
8781 /*  9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1, FALSE },
8782 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2, FALSE },
8783 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1, FALSE },
8784 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq, FALSE },
8785 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1, FALSE },
8786 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
8787 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2, FALSE },
8788 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
8789 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow, FALSE },
8790 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
8791 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1, TRUE },
8792 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
8793 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
8794 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate, TRUE },
8795 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4, FALSE },
8796 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
8797 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
8798 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1, FALSE },
8799 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2, FALSE },
8800 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
8801 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
8802 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1, FALSE },
8803 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
8804 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3, TRUE },
8805 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
8806 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, TRUE }, /* what does this mean?! */
8807 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, TRUE },
8808 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
8809 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2, FALSE },
8810 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
8811 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
8812 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2, TRUE },
8813 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
8814 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2, TRUE },
8815 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2, FALSE },
8816 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1, TRUE },
8817 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
8818 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3, FALSE },
8819 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4, FALSE },
8820 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3, FALSE },
8821 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq, FALSE },
8822 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5, FALSE },
8823 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
8824 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1, FALSE },
8825 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
8826 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3, TRUE },
8827 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
8828 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2, FALSE },
8829 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq, FALSE }
8830     };
8831     HWND hwnd;
8832     DWORD style;
8833     LPARAM ret;
8834     INT i;
8835
8836 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
8837     hwnd = CreateWindowEx(0, "ShowWindowClass", NULL, WS_BASE,
8838                           120, 120, 90, 90,
8839                           0, 0, 0, NULL);
8840     assert(hwnd);
8841
8842     style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
8843     ok(style == 0, "expected style 0, got %08x\n", style);
8844
8845     flush_events();
8846     flush_sequence();
8847
8848     for (i = 0; i < sizeof(sw)/sizeof(sw[0]); i++)
8849     {
8850         static const char * const sw_cmd_name[13] =
8851         {
8852             "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
8853             "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
8854             "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
8855             "SW_NORMALNA" /* 0xCC */
8856         };
8857         char comment[64];
8858         INT idx; /* index into the above array of names */
8859
8860         idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
8861
8862         style = GetWindowLong(hwnd, GWL_STYLE);
8863         trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
8864         ret = ShowWindow(hwnd, sw[i].cmd);
8865         ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
8866         style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
8867         ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
8868
8869         sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
8870         ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
8871
8872         flush_events();
8873         flush_sequence();
8874     }
8875
8876     DestroyWindow(hwnd);
8877 }
8878
8879 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8880 {
8881     struct message msg;
8882
8883     trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
8884
8885     switch (message)
8886     {
8887     case WM_WINDOWPOSCHANGING:
8888     case WM_WINDOWPOSCHANGED:
8889     {
8890         WINDOWPOS *winpos = (WINDOWPOS *)lParam;
8891
8892         trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
8893         trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
8894               winpos->hwnd, winpos->hwndInsertAfter,
8895               winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
8896         dump_winpos_flags(winpos->flags);
8897
8898         /* Log only documented flags, win2k uses 0x1000 and 0x2000
8899          * in the high word for internal purposes
8900          */
8901         wParam = winpos->flags & 0xffff;
8902         /* We are not interested in the flags that don't match under XP and Win9x */
8903         wParam &= ~(SWP_NOZORDER);
8904         break;
8905     }
8906
8907     /* explicitly ignore WM_GETICON message */
8908     case WM_GETICON:
8909         return 0;
8910     }
8911
8912     msg.message = message;
8913     msg.flags = sent|wparam|lparam;
8914     msg.wParam = wParam;
8915     msg.lParam = lParam;
8916     add_message(&msg);
8917
8918     /* calling DefDlgProc leads to a recursion under XP */
8919
8920     switch (message)
8921     {
8922     case WM_INITDIALOG:
8923     case WM_GETDLGCODE:
8924         return 0;
8925     }
8926     return 1;
8927 }
8928
8929 static const struct message WmDefDlgSetFocus_1[] = {
8930     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
8931     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
8932     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
8933     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
8934     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
8935     { HCBT_SETFOCUS, hook },
8936     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
8937     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8938     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8939     { WM_SETFOCUS, sent|wparam, 0 },
8940     { WM_CTLCOLOREDIT, sent },
8941     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8942     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8943     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8944     { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
8945     { 0 }
8946 };
8947 static const struct message WmDefDlgSetFocus_2[] = {
8948     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
8949     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
8950     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
8951     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
8952     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
8953     { WM_CTLCOLOREDIT, sent|optional }, /* XP */
8954     { 0 }
8955 };
8956 /* Creation of a dialog */
8957 static const struct message WmCreateDialogParamSeq_1[] = {
8958     { HCBT_CREATEWND, hook },
8959     { WM_NCCREATE, sent },
8960     { WM_NCCALCSIZE, sent|wparam, 0 },
8961     { WM_CREATE, sent },
8962     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
8963     { WM_SIZE, sent|wparam, SIZE_RESTORED },
8964     { WM_MOVE, sent },
8965     { WM_SETFONT, sent },
8966     { WM_INITDIALOG, sent },
8967     { WM_CHANGEUISTATE, sent|optional },
8968     { 0 }
8969 };
8970 /* Creation of a dialog */
8971 static const struct message WmCreateDialogParamSeq_2[] = {
8972     { HCBT_CREATEWND, hook },
8973     { WM_NCCREATE, sent },
8974     { WM_NCCALCSIZE, sent|wparam, 0 },
8975     { WM_CREATE, sent },
8976     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
8977     { WM_SIZE, sent|wparam, SIZE_RESTORED },
8978     { WM_MOVE, sent },
8979     { WM_CHANGEUISTATE, sent|optional },
8980     { 0 }
8981 };
8982
8983 static void test_dialog_messages(void)
8984 {
8985     WNDCLASS cls;
8986     HWND hdlg, hedit1, hedit2, hfocus;
8987     LRESULT ret;
8988
8989 #define set_selection(hctl, start, end) \
8990     ret = SendMessage(hctl, EM_SETSEL, start, end); \
8991     ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
8992
8993 #define check_selection(hctl, start, end) \
8994     ret = SendMessage(hctl, EM_GETSEL, 0, 0); \
8995     ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
8996
8997     subclass_edit();
8998
8999     hdlg = CreateWindowEx(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
9000                           WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
9001                           0, 0, 100, 100, 0, 0, 0, NULL);
9002     ok(hdlg != 0, "Failed to create custom dialog window\n");
9003
9004     hedit1 = CreateWindowEx(0, "my_edit_class", NULL,
9005                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
9006                            0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
9007     ok(hedit1 != 0, "Failed to create edit control\n");
9008     hedit2 = CreateWindowEx(0, "my_edit_class", NULL,
9009                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
9010                            0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
9011     ok(hedit2 != 0, "Failed to create edit control\n");
9012
9013     SendMessage(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
9014     SendMessage(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
9015
9016     hfocus = GetFocus();
9017     ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
9018
9019     SetFocus(hedit2);
9020     hfocus = GetFocus();
9021     ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
9022
9023     check_selection(hedit1, 0, 0);
9024     check_selection(hedit2, 0, 0);
9025
9026     set_selection(hedit2, 0, -1);
9027     check_selection(hedit2, 0, 3);
9028
9029     SetFocus(0);
9030     hfocus = GetFocus();
9031     ok(hfocus == 0, "wrong focus %p\n", hfocus);
9032
9033     flush_sequence();
9034     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
9035     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
9036     ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
9037
9038     hfocus = GetFocus();
9039     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
9040
9041     check_selection(hedit1, 0, 5);
9042     check_selection(hedit2, 0, 3);
9043
9044     flush_sequence();
9045     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
9046     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
9047     ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
9048
9049     hfocus = GetFocus();
9050     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
9051
9052     check_selection(hedit1, 0, 5);
9053     check_selection(hedit2, 0, 3);
9054
9055     EndDialog(hdlg, 0);
9056     flush_sequence();
9057
9058 #undef set_selection
9059 #undef check_selection
9060
9061     ok(GetClassInfo(0, "#32770", &cls), "GetClassInfo failed\n");
9062     cls.lpszClassName = "MyDialogClass";
9063     cls.hInstance = GetModuleHandle(0);
9064     /* need a cast since a dlgproc is used as a wndproc */
9065     cls.lpfnWndProc = (WNDPROC)test_dlg_proc;
9066     if (!RegisterClass(&cls)) assert(0);
9067
9068     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
9069     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
9070     ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
9071     EndDialog(hdlg, 0);
9072     flush_sequence();
9073
9074     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
9075     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
9076     ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
9077     EndDialog(hdlg, 0);
9078     flush_sequence();
9079
9080     UnregisterClass(cls.lpszClassName, cls.hInstance);
9081 }
9082
9083 static void test_nullCallback(void)
9084 {
9085     HWND hwnd;
9086     MSG msg;
9087
9088     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
9089                            100, 100, 200, 200, 0, 0, 0, NULL);
9090     ok (hwnd != 0, "Failed to create overlapped window\n");
9091
9092     SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
9093     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
9094     DestroyWindow(hwnd);
9095 }
9096
9097 START_TEST(msg)
9098 {
9099     BOOL ret;
9100     HMODULE user32 = GetModuleHandleA("user32.dll");
9101     FARPROC pSetWinEventHook = GetProcAddress(user32, "SetWinEventHook");
9102     FARPROC pUnhookWinEvent = GetProcAddress(user32, "UnhookWinEvent");
9103     FARPROC pIsWinEventHookInstalled = 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
9104     pGetAncestor = (void*) GetProcAddress(user32, "GetAncestor");
9105
9106     if (!RegisterWindowClasses()) assert(0);
9107
9108     if (pSetWinEventHook)
9109     {
9110         hEvent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
9111                                                       GetModuleHandleA(0),
9112                                                       win_event_proc,
9113                                                       0,
9114                                                       GetCurrentThreadId(),
9115                                                       WINEVENT_INCONTEXT);
9116         assert(hEvent_hook);
9117
9118         if (pIsWinEventHookInstalled)
9119         {
9120             UINT event;
9121             for (event = EVENT_MIN; event <= EVENT_MAX; event++)
9122                 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
9123         }
9124     }
9125
9126     cbt_hook_thread_id = GetCurrentThreadId();
9127     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
9128     assert(hCBT_hook);
9129
9130     test_winevents();
9131
9132     /* Fix message sequences before removing 4 lines below */
9133 #if 1
9134     if (pUnhookWinEvent && hEvent_hook)
9135     {
9136         ret = pUnhookWinEvent(hEvent_hook);
9137         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
9138         pUnhookWinEvent = 0;
9139     }
9140     hEvent_hook = 0;
9141 #endif
9142
9143     test_ShowWindow();
9144     test_PeekMessage();
9145     test_scrollwindowex();
9146     test_messages();
9147     test_showwindow();
9148     invisible_parent_tests();
9149     test_mdi_messages();
9150     test_button_messages();
9151     test_static_messages();
9152     test_paint_messages();
9153     test_interthread_messages();
9154     test_message_conversion();
9155     test_accelerators();
9156     test_timers();
9157     test_set_hook();
9158     test_DestroyWindow();
9159     test_DispatchMessage();
9160     test_SendMessageTimeout();
9161     test_edit_messages();
9162     test_quit_message();
9163     test_TrackMouseEvent();
9164     test_SetWindowRgn();
9165     test_sys_menu();
9166     test_dialog_messages();
9167     test_nullCallback();
9168
9169     UnhookWindowsHookEx(hCBT_hook);
9170     if (pUnhookWinEvent)
9171     {
9172         ret = pUnhookWinEvent(hEvent_hook);
9173         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
9174         SetLastError(0xdeadbeef);
9175         ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
9176         ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
9177            GetLastError() == 0xdeadbeef, /* Win9x */
9178            "unexpected error %d\n", GetLastError());
9179     }
9180 }