wintrust: Implement WintrustLoadFunctionPointers.
[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|parent|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, "#32770"))
6325         {
6326             struct message msg;
6327
6328             msg.message = nCode;
6329             msg.flags = hook|wparam|lparam;
6330             msg.wParam = wParam;
6331             msg.lParam = lParam;
6332             add_message(&msg);
6333         }
6334     }
6335     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
6336 }
6337
6338 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
6339                                     DWORD event,
6340                                     HWND hwnd,
6341                                     LONG object_id,
6342                                     LONG child_id,
6343                                     DWORD thread_id,
6344                                     DWORD event_time)
6345 {
6346     char buf[256];
6347
6348     trace("WEH:%p,event %08x,hwnd %p,obj %08x,id %08x,thread %08x,time %08x\n",
6349            hevent, event, hwnd, object_id, child_id, thread_id, event_time);
6350
6351     ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
6352
6353     /* ignore mouse cursor events */
6354     if (object_id == OBJID_CURSOR) return;
6355
6356     if (!hwnd || GetClassNameA(hwnd, buf, sizeof(buf)))
6357     {
6358         if (!hwnd ||
6359             !lstrcmpiA(buf, "TestWindowClass") ||
6360             !lstrcmpiA(buf, "TestParentClass") ||
6361             !lstrcmpiA(buf, "TestPopupClass") ||
6362             !lstrcmpiA(buf, "SimpleWindowClass") ||
6363             !lstrcmpiA(buf, "TestDialogClass") ||
6364             !lstrcmpiA(buf, "MDI_frame_class") ||
6365             !lstrcmpiA(buf, "MDI_client_class") ||
6366             !lstrcmpiA(buf, "MDI_child_class") ||
6367             !lstrcmpiA(buf, "my_button_class") ||
6368             !lstrcmpiA(buf, "my_edit_class") ||
6369             !lstrcmpiA(buf, "static") ||
6370             !lstrcmpiA(buf, "#32770"))
6371         {
6372             struct message msg;
6373
6374             msg.message = event;
6375             msg.flags = winevent_hook|wparam|lparam;
6376             msg.wParam = object_id;
6377             msg.lParam = child_id;
6378             add_message(&msg);
6379         }
6380     }
6381 }
6382
6383 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
6384 static const WCHAR wszAnsi[] = {'U',0};
6385
6386 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
6387 {
6388     switch (uMsg)
6389     {
6390     case CB_FINDSTRINGEXACT:
6391         trace("String: %p\n", (LPCWSTR)lParam);
6392         if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
6393             return 1;
6394         if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
6395             return 0;
6396         return -1;
6397     }
6398     return DefWindowProcW(hwnd, uMsg, wParam, lParam);
6399 }
6400
6401 static const struct message WmGetTextLengthAfromW[] = {
6402     { WM_GETTEXTLENGTH, sent },
6403     { WM_GETTEXT, sent },
6404     { 0 }
6405 };
6406
6407 static const WCHAR testWindowClassW[] = 
6408 { 'T','e','s','t','W','i','n','d','o','w','C','l','a','s','s','W',0 };
6409
6410 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
6411
6412 /* dummy window proc for WM_GETTEXTLENGTH test */
6413 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
6414 {
6415     switch(msg)
6416     {
6417     case WM_GETTEXTLENGTH:
6418         return lstrlenW(dummy_window_text) + 37;  /* some random length */
6419     case WM_GETTEXT:
6420         lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
6421         return lstrlenW( (LPWSTR)lp );
6422     default:
6423         return DefWindowProcW( hwnd, msg, wp, lp );
6424     }
6425 }
6426
6427 static void test_message_conversion(void)
6428 {
6429     static const WCHAR wszMsgConversionClass[] =
6430         {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
6431     WNDCLASSW cls;
6432     LRESULT lRes;
6433     HWND hwnd;
6434     WNDPROC wndproc, newproc;
6435     BOOL ret;
6436
6437     cls.style = 0;
6438     cls.lpfnWndProc = MsgConversionProcW;
6439     cls.cbClsExtra = 0;
6440     cls.cbWndExtra = 0;
6441     cls.hInstance = GetModuleHandleW(NULL);
6442     cls.hIcon = NULL;
6443     cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
6444     cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
6445     cls.lpszMenuName = NULL;
6446     cls.lpszClassName = wszMsgConversionClass;
6447     /* this call will fail on Win9x, but that doesn't matter as this test is
6448      * meaningless on those platforms */
6449     if(!RegisterClassW(&cls)) return;
6450
6451     cls.style = 0;
6452     cls.lpfnWndProc = MsgCheckProcW;
6453     cls.cbClsExtra = 0;
6454     cls.cbWndExtra = 0;
6455     cls.hInstance = GetModuleHandleW(0);
6456     cls.hIcon = 0;
6457     cls.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
6458     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
6459     cls.lpszMenuName = NULL;
6460     cls.lpszClassName = testWindowClassW;
6461     if(!RegisterClassW(&cls)) return;
6462
6463     hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
6464                            100, 100, 200, 200, 0, 0, 0, NULL);
6465     ok(hwnd != NULL, "Window creation failed\n");
6466
6467     /* {W, A} -> A */
6468
6469     wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
6470     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6471     ok(lRes == 0, "String should have been converted\n");
6472     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6473     ok(lRes == 1, "String shouldn't have been converted\n");
6474
6475     /* {W, A} -> W */
6476
6477     wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
6478     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6479     ok(lRes == 1, "String shouldn't have been converted\n");
6480     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6481     ok(lRes == 1, "String shouldn't have been converted\n");
6482
6483     /* Synchronous messages */
6484
6485     lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6486     ok(lRes == 0, "String should have been converted\n");
6487     lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6488     ok(lRes == 1, "String shouldn't have been converted\n");
6489
6490     /* Asynchronous messages */
6491
6492     SetLastError(0);
6493     lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6494     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6495         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6496     SetLastError(0);
6497     lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6498     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6499         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6500     SetLastError(0);
6501     lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6502     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6503         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6504     SetLastError(0);
6505     lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6506     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6507         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6508     SetLastError(0);
6509     lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6510     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6511         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6512     SetLastError(0);
6513     lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6514     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6515         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6516     SetLastError(0);
6517     lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
6518     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6519         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6520     SetLastError(0);
6521     lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
6522     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6523         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6524
6525     /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
6526
6527     hwnd = CreateWindowW (testWindowClassW, wszUnicode,
6528                           WS_OVERLAPPEDWINDOW,
6529                           100, 100, 200, 200, 0, 0, 0, NULL);
6530     assert(hwnd);
6531     flush_sequence();
6532     lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
6533     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
6534     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
6535         "got bad length %ld\n", lRes );
6536
6537     flush_sequence();
6538     lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
6539                             hwnd, WM_GETTEXTLENGTH, 0, 0);
6540     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
6541     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
6542         "got bad length %ld\n", lRes );
6543
6544     wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
6545     newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
6546     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
6547     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
6548                                      NULL, 0, NULL, NULL ),
6549         "got bad length %ld\n", lRes );
6550
6551     SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc );  /* restore old wnd proc */
6552     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
6553     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
6554                                      NULL, 0, NULL, NULL ),
6555         "got bad length %ld\n", lRes );
6556
6557     ret = DestroyWindow(hwnd);
6558     ok( ret, "DestroyWindow() error %d\n", GetLastError());
6559 }
6560
6561 struct timer_info
6562 {
6563     HWND hWnd;
6564     HANDLE handles[2];
6565     DWORD id;
6566 };
6567
6568 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT id, DWORD dwTime)
6569 {
6570 }
6571
6572 #define TIMER_ID  0x19
6573
6574 static DWORD WINAPI timer_thread_proc(LPVOID x)
6575 {
6576     struct timer_info *info = x;
6577     DWORD r;
6578
6579     r = KillTimer(info->hWnd, 0x19);
6580     ok(r,"KillTimer failed in thread\n");
6581     r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
6582     ok(r,"SetTimer failed in thread\n");
6583     ok(r==TIMER_ID,"SetTimer id different\n");
6584     r = SetEvent(info->handles[0]);
6585     ok(r,"SetEvent failed in thread\n");
6586     return 0;
6587 }
6588
6589 static void test_timers(void)
6590 {
6591     struct timer_info info;
6592     DWORD id;
6593
6594     info.hWnd = CreateWindow ("TestWindowClass", NULL,
6595        WS_OVERLAPPEDWINDOW ,
6596        CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
6597        NULL, NULL, 0);
6598
6599     info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
6600     ok(info.id, "SetTimer failed\n");
6601     ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
6602     info.handles[0] = CreateEvent(NULL,0,0,NULL);
6603     info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
6604
6605     WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
6606
6607     WaitForSingleObject(info.handles[1], INFINITE);
6608
6609     CloseHandle(info.handles[0]);
6610     CloseHandle(info.handles[1]);
6611
6612     ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
6613
6614     ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
6615 }
6616
6617 /* Various win events with arbitrary parameters */
6618 static const struct message WmWinEventsSeq[] = {
6619     { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
6620     { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
6621     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
6622     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
6623     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
6624     { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
6625     { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
6626     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
6627     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
6628     /* our win event hook ignores OBJID_CURSOR events */
6629     /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
6630     { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
6631     { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
6632     { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
6633     { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
6634     { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
6635     { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
6636     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
6637     { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
6638     { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
6639     { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
6640     { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
6641     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
6642     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
6643     { 0 }
6644 };
6645 static const struct message WmWinEventCaretSeq[] = {
6646     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
6647     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
6648     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
6649     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
6650     { 0 }
6651 };
6652 static const struct message WmWinEventCaretSeq_2[] = {
6653     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
6654     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
6655     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
6656     { 0 }
6657 };
6658 static const struct message WmWinEventAlertSeq[] = {
6659     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
6660     { 0 }
6661 };
6662 static const struct message WmWinEventAlertSeq_2[] = {
6663     /* create window in the thread proc */
6664     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
6665     /* our test event */
6666     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
6667     { 0 }
6668 };
6669 static const struct message WmGlobalHookSeq_1[] = {
6670     /* create window in the thread proc */
6671     { HCBT_CREATEWND, hook|lparam, 0, 2 },
6672     /* our test events */
6673     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
6674     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
6675     { 0 }
6676 };
6677 static const struct message WmGlobalHookSeq_2[] = {
6678     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
6679     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
6680     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
6681     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
6682     { 0 }
6683 };
6684
6685 static const struct message WmMouseLLHookSeq[] = {
6686     { WM_MOUSEMOVE, hook },
6687     { WM_LBUTTONUP, hook },
6688     { WM_MOUSEMOVE, hook },
6689     { 0 }
6690 };
6691
6692 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
6693                                          DWORD event,
6694                                          HWND hwnd,
6695                                          LONG object_id,
6696                                          LONG child_id,
6697                                          DWORD thread_id,
6698                                          DWORD event_time)
6699 {
6700     char buf[256];
6701
6702     trace("WEH_2:%p,event %08x,hwnd %p,obj %08x,id %08x,thread %08x,time %08x\n",
6703            hevent, event, hwnd, object_id, child_id, thread_id, event_time);
6704
6705     if (GetClassNameA(hwnd, buf, sizeof(buf)))
6706     {
6707         if (!lstrcmpiA(buf, "TestWindowClass") ||
6708             !lstrcmpiA(buf, "static"))
6709         {
6710             struct message msg;
6711
6712             msg.message = event;
6713             msg.flags = winevent_hook|wparam|lparam;
6714             msg.wParam = object_id;
6715             msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
6716             add_message(&msg);
6717         }
6718     }
6719 }
6720
6721 static HHOOK hCBT_global_hook;
6722 static DWORD cbt_global_hook_thread_id;
6723
6724 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
6725
6726     HWND hwnd;
6727     char buf[256];
6728
6729     trace("CBT_2: %d, %08x, %08lx\n", nCode, wParam, lParam);
6730
6731     if (nCode == HCBT_SYSCOMMAND)
6732     {
6733         struct message msg;
6734
6735         msg.message = nCode;
6736         msg.flags = hook|wparam|lparam;
6737         msg.wParam = wParam;
6738         msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
6739         add_message(&msg);
6740
6741         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
6742     }
6743     /* WH_MOUSE_LL hook */
6744     if (nCode == HC_ACTION)
6745     {
6746         struct message msg;
6747         MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
6748
6749         /* we can't test for real mouse events */
6750         if (mhll->flags & LLMHF_INJECTED)
6751         {
6752             msg.message = wParam;
6753             msg.flags = hook;
6754             add_message(&msg);
6755         }
6756         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
6757     }
6758
6759     /* Log also SetFocus(0) calls */
6760     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
6761
6762     if (GetClassNameA(hwnd, buf, sizeof(buf)))
6763     {
6764         if (!lstrcmpiA(buf, "TestWindowClass") ||
6765             !lstrcmpiA(buf, "static"))
6766         {
6767             struct message msg;
6768
6769             msg.message = nCode;
6770             msg.flags = hook|wparam|lparam;
6771             msg.wParam = wParam;
6772             msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
6773             add_message(&msg);
6774         }
6775     }
6776     return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
6777 }
6778
6779 static DWORD WINAPI win_event_global_thread_proc(void *param)
6780 {
6781     HWND hwnd;
6782     MSG msg;
6783     HANDLE hevent = *(HANDLE *)param;
6784     HMODULE user32 = GetModuleHandleA("user32.dll");
6785     FARPROC pNotifyWinEvent = GetProcAddress(user32, "NotifyWinEvent");
6786
6787     assert(pNotifyWinEvent);
6788
6789     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
6790     assert(hwnd);
6791     trace("created thread window %p\n", hwnd);
6792
6793     *(HWND *)param = hwnd;
6794
6795     flush_sequence();
6796     /* this event should be received only by our new hook proc,
6797      * an old one does not expect an event from another thread.
6798      */
6799     pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
6800     SetEvent(hevent);
6801
6802     while (GetMessage(&msg, 0, 0, 0))
6803     {
6804         TranslateMessage(&msg);
6805         DispatchMessage(&msg);
6806     }
6807     return 0;
6808 }
6809
6810 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
6811 {
6812     HWND hwnd;
6813     MSG msg;
6814     HANDLE hevent = *(HANDLE *)param;
6815
6816     flush_sequence();
6817     /* these events should be received only by our new hook proc,
6818      * an old one does not expect an event from another thread.
6819      */
6820
6821     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
6822     assert(hwnd);
6823     trace("created thread window %p\n", hwnd);
6824
6825     *(HWND *)param = hwnd;
6826
6827     /* Windows doesn't like when a thread plays games with the focus,
6828        that leads to all kinds of misbehaviours and failures to activate
6829        a window. So, better keep next lines commented out.
6830     SetFocus(0);
6831     SetFocus(hwnd);*/
6832
6833     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
6834     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
6835
6836     SetEvent(hevent);
6837
6838     while (GetMessage(&msg, 0, 0, 0))
6839     {
6840         TranslateMessage(&msg);
6841         DispatchMessage(&msg);
6842     }
6843     return 0;
6844 }
6845
6846 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
6847 {
6848     HWND hwnd;
6849     MSG msg;
6850     HANDLE hevent = *(HANDLE *)param;
6851
6852     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
6853     assert(hwnd);
6854     trace("created thread window %p\n", hwnd);
6855
6856     *(HWND *)param = hwnd;
6857
6858     flush_sequence();
6859
6860     /* Windows doesn't like when a thread plays games with the focus,
6861      * that leads to all kinds of misbehaviours and failures to activate
6862      * a window. So, better don't generate a mouse click message below.
6863      */
6864     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
6865     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
6866     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
6867
6868     SetEvent(hevent);
6869     while (GetMessage(&msg, 0, 0, 0))
6870     {
6871         TranslateMessage(&msg);
6872         DispatchMessage(&msg);
6873     }
6874     return 0;
6875 }
6876
6877 static void test_winevents(void)
6878 {
6879     BOOL ret;
6880     MSG msg;
6881     HWND hwnd, hwnd2;
6882     UINT i;
6883     HANDLE hthread, hevent;
6884     DWORD tid;
6885     HWINEVENTHOOK hhook;
6886     const struct message *events = WmWinEventsSeq;
6887     HMODULE user32 = GetModuleHandleA("user32.dll");
6888     FARPROC pSetWinEventHook = GetProcAddress(user32, "SetWinEventHook");
6889     FARPROC pUnhookWinEvent = GetProcAddress(user32, "UnhookWinEvent");
6890     FARPROC pNotifyWinEvent = GetProcAddress(user32, "NotifyWinEvent");
6891
6892     hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
6893                            WS_OVERLAPPEDWINDOW,
6894                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
6895                            NULL, NULL, 0);
6896     assert(hwnd);
6897
6898     /****** start of global hook test *************/
6899     hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
6900     assert(hCBT_global_hook);
6901
6902     hevent = CreateEventA(NULL, 0, 0, NULL);
6903     assert(hevent);
6904     hwnd2 = (HWND)hevent;
6905
6906     hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
6907     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
6908
6909     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6910
6911     ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
6912
6913     flush_sequence();
6914     /* this one should be received only by old hook proc */
6915     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
6916     /* this one should be received only by old hook proc */
6917     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
6918
6919     ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
6920
6921     ret = UnhookWindowsHookEx(hCBT_global_hook);
6922     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
6923
6924     PostThreadMessageA(tid, WM_QUIT, 0, 0);
6925     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6926     CloseHandle(hthread);
6927     CloseHandle(hevent);
6928     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
6929     /****** end of global hook test *************/
6930
6931     if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
6932     {
6933         ok(DestroyWindow(hwnd), "failed to destroy window\n");
6934         return;
6935     }
6936
6937     flush_sequence();
6938
6939     if (0)
6940     {
6941     /* this test doesn't pass under Win9x */
6942     /* win2k ignores events with hwnd == 0 */
6943     SetLastError(0xdeadbeef);
6944     pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
6945     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
6946        GetLastError() == 0xdeadbeef, /* Win9x */
6947        "unexpected error %d\n", GetLastError());
6948     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
6949     }
6950
6951     for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++)
6952         pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
6953
6954     ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
6955
6956     /****** start of event filtering test *************/
6957     hhook = (HWINEVENTHOOK)pSetWinEventHook(
6958         EVENT_OBJECT_SHOW, /* 0x8002 */
6959         EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
6960         GetModuleHandleA(0), win_event_global_hook_proc,
6961         GetCurrentProcessId(), 0,
6962         WINEVENT_INCONTEXT);
6963     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
6964
6965     hevent = CreateEventA(NULL, 0, 0, NULL);
6966     assert(hevent);
6967     hwnd2 = (HWND)hevent;
6968
6969     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
6970     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
6971
6972     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6973
6974     ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
6975
6976     flush_sequence();
6977     /* this one should be received only by old hook proc */
6978     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
6979     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
6980     /* this one should be received only by old hook proc */
6981     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
6982
6983     ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
6984
6985     ret = pUnhookWinEvent(hhook);
6986     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
6987
6988     PostThreadMessageA(tid, WM_QUIT, 0, 0);
6989     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6990     CloseHandle(hthread);
6991     CloseHandle(hevent);
6992     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
6993     /****** end of event filtering test *************/
6994
6995     /****** start of out of context event test *************/
6996     hhook = (HWINEVENTHOOK)pSetWinEventHook(
6997         EVENT_MIN, EVENT_MAX,
6998         0, win_event_global_hook_proc,
6999         GetCurrentProcessId(), 0,
7000         WINEVENT_OUTOFCONTEXT);
7001     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
7002
7003     hevent = CreateEventA(NULL, 0, 0, NULL);
7004     assert(hevent);
7005     hwnd2 = (HWND)hevent;
7006
7007     flush_sequence();
7008
7009     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
7010     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7011
7012     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7013
7014     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
7015     /* process pending winevent messages */
7016     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
7017     ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
7018
7019     flush_sequence();
7020     /* this one should be received only by old hook proc */
7021     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
7022     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
7023     /* this one should be received only by old hook proc */
7024     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
7025
7026     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
7027     /* process pending winevent messages */
7028     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
7029     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
7030
7031     ret = pUnhookWinEvent(hhook);
7032     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
7033
7034     PostThreadMessageA(tid, WM_QUIT, 0, 0);
7035     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7036     CloseHandle(hthread);
7037     CloseHandle(hevent);
7038     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7039     /****** end of out of context event test *************/
7040
7041     /****** start of MOUSE_LL hook test *************/
7042     hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
7043     /* WH_MOUSE_LL is not supported on Win9x platforms */
7044     if (!hCBT_global_hook)
7045     {
7046         trace("Skipping WH_MOUSE_LL test on this platform\n");
7047         goto skip_mouse_ll_hook_test;
7048     }
7049
7050     hevent = CreateEventA(NULL, 0, 0, NULL);
7051     assert(hevent);
7052     hwnd2 = (HWND)hevent;
7053
7054     hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
7055     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7056
7057     while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
7058         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
7059
7060     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
7061     flush_sequence();
7062
7063     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
7064     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
7065     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
7066
7067     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
7068
7069     ret = UnhookWindowsHookEx(hCBT_global_hook);
7070     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
7071
7072     PostThreadMessageA(tid, WM_QUIT, 0, 0);
7073     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7074     CloseHandle(hthread);
7075     CloseHandle(hevent);
7076     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7077     /****** end of MOUSE_LL hook test *************/
7078 skip_mouse_ll_hook_test:
7079
7080     ok(DestroyWindow(hwnd), "failed to destroy window\n");
7081 }
7082
7083 static void test_set_hook(void)
7084 {
7085     BOOL ret;
7086     HHOOK hhook;
7087     HWINEVENTHOOK hwinevent_hook;
7088     HMODULE user32 = GetModuleHandleA("user32.dll");
7089     FARPROC pSetWinEventHook = GetProcAddress(user32, "SetWinEventHook");
7090     FARPROC pUnhookWinEvent = GetProcAddress(user32, "UnhookWinEvent");
7091
7092     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
7093     ok(hhook != 0, "local hook does not require hModule set to 0\n");
7094     UnhookWindowsHookEx(hhook);
7095
7096     if (0)
7097     {
7098     /* this test doesn't pass under Win9x: BUG! */
7099     SetLastError(0xdeadbeef);
7100     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
7101     ok(!hhook, "global hook requires hModule != 0\n");
7102     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
7103     }
7104
7105     SetLastError(0xdeadbeef);
7106     hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
7107     ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
7108     ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
7109        GetLastError() == 0xdeadbeef, /* Win9x */
7110        "unexpected error %d\n", GetLastError());
7111
7112     SetLastError(0xdeadbeef);
7113     ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
7114     ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
7115        GetLastError() == 0xdeadbeef, /* Win9x */
7116        "unexpected error %d\n", GetLastError());
7117
7118     if (!pSetWinEventHook || !pUnhookWinEvent) return;
7119
7120     /* even process local incontext hooks require hmodule */
7121     SetLastError(0xdeadbeef);
7122     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
7123         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
7124     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
7125     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
7126        GetLastError() == 0xdeadbeef, /* Win9x */
7127        "unexpected error %d\n", GetLastError());
7128
7129     /* even thread local incontext hooks require hmodule */
7130     SetLastError(0xdeadbeef);
7131     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
7132         0, win_event_proc, GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
7133     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
7134     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
7135        GetLastError() == 0xdeadbeef, /* Win9x */
7136        "unexpected error %d\n", GetLastError());
7137
7138     if (0)
7139     {
7140     /* these 3 tests don't pass under Win9x */
7141     SetLastError(0xdeadbeef);
7142     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(1, 0,
7143         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
7144     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
7145     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
7146
7147     SetLastError(0xdeadbeef);
7148     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(-1, 1,
7149         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
7150     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
7151     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
7152
7153     SetLastError(0xdeadbeef);
7154     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
7155         0, win_event_proc, 0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
7156     ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
7157     ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
7158     }
7159
7160     SetLastError(0xdeadbeef);
7161     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(0, 0,
7162         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
7163     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
7164     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
7165     ret = pUnhookWinEvent(hwinevent_hook);
7166     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
7167
7168 todo_wine {
7169     /* This call succeeds under win2k SP4, but fails under Wine.
7170        Does win2k test/use passed process id? */
7171     SetLastError(0xdeadbeef);
7172     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
7173         0, win_event_proc, 0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
7174     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
7175     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
7176     ret = pUnhookWinEvent(hwinevent_hook);
7177     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
7178 }
7179
7180     SetLastError(0xdeadbeef);
7181     ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
7182     ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
7183         GetLastError() == 0xdeadbeef, /* Win9x */
7184         "unexpected error %d\n", GetLastError());
7185 }
7186
7187 static const struct message ScrollWindowPaint1[] = {
7188     { WM_PAINT, sent },
7189     { WM_ERASEBKGND, sent|beginpaint },
7190     { 0 }
7191 };
7192
7193 static const struct message ScrollWindowPaint2[] = {
7194     { WM_PAINT, sent },
7195     { 0 }
7196 };
7197
7198 static void test_scrollwindowex(void)
7199 {
7200     HWND hwnd, hchild;
7201     RECT rect={0,0,130,130};
7202     MSG msg;
7203
7204     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
7205             WS_VISIBLE|WS_OVERLAPPEDWINDOW,
7206             100, 100, 200, 200, 0, 0, 0, NULL);
7207     ok (hwnd != 0, "Failed to create overlapped window\n");
7208     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", 
7209             WS_VISIBLE|WS_CAPTION|WS_CHILD,
7210             10, 10, 150, 150, hwnd, 0, 0, NULL);
7211     ok (hchild != 0, "Failed to create child\n");
7212     UpdateWindow(hwnd);
7213     flush_events();
7214     flush_sequence();
7215
7216     /* scroll without the child window */
7217     trace("start scroll\n");
7218     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
7219             SW_ERASE|SW_INVALIDATE);
7220     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
7221     trace("end scroll\n");
7222     flush_sequence();
7223     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
7224     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
7225     flush_events();
7226     flush_sequence();
7227
7228     /* Now without the SW_ERASE flag */
7229     trace("start scroll\n");
7230     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
7231     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
7232     trace("end scroll\n");
7233     flush_sequence();
7234     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
7235     ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", 0);
7236     flush_events();
7237     flush_sequence();
7238
7239     /* now scroll the child window as well */
7240     trace("start scroll\n");
7241     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
7242             SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
7243     todo_wine { /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
7244                 /* windows sometimes a WM_MOVE */
7245         ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
7246     }
7247     trace("end scroll\n");
7248     flush_sequence();
7249     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
7250     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
7251     flush_events();
7252     flush_sequence();
7253
7254     /* now scroll with ScrollWindow() */
7255     trace("start scroll with ScrollWindow\n");
7256     ScrollWindow( hwnd, 5, 5, NULL, NULL);
7257     trace("end scroll\n");
7258     flush_sequence();
7259     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
7260     ok_sequence(ScrollWindowPaint1, "ScrollWindow", 0);
7261
7262     ok(DestroyWindow(hchild), "failed to destroy window\n");
7263     ok(DestroyWindow(hwnd), "failed to destroy window\n");
7264     flush_sequence();
7265 }
7266
7267 static const struct message destroy_window_with_children[] = {
7268     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
7269     { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
7270     { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
7271     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
7272     { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
7273     { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
7274     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
7275     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
7276     { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
7277     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
7278     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
7279     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
7280     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
7281     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
7282     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
7283     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
7284     { 0 }
7285 };
7286
7287 static void test_DestroyWindow(void)
7288 {
7289     BOOL ret;
7290     HWND parent, child1, child2, child3, child4, test;
7291     UINT child_id = WND_CHILD_ID + 1;
7292
7293     parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
7294                              100, 100, 200, 200, 0, 0, 0, NULL);
7295     assert(parent != 0);
7296     child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
7297                              0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
7298     assert(child1 != 0);
7299     child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
7300                              0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
7301     assert(child2 != 0);
7302     child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
7303                              0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
7304     assert(child3 != 0);
7305     child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
7306                              0, 0, 50, 50, parent, 0, 0, NULL);
7307     assert(child4 != 0);
7308
7309     /* test owner/parent of child2 */
7310     test = GetParent(child2);
7311     ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
7312     ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
7313     if(pGetAncestor) {
7314         test = pGetAncestor(child2, GA_PARENT);
7315         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
7316     }
7317     test = GetWindow(child2, GW_OWNER);
7318     ok(!test, "wrong owner %p\n", test);
7319
7320     test = SetParent(child2, parent);
7321     ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
7322
7323     /* test owner/parent of the parent */
7324     test = GetParent(parent);
7325     ok(!test, "wrong parent %p\n", test);
7326 todo_wine {
7327     ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
7328 }
7329     if(pGetAncestor) {
7330         test = pGetAncestor(parent, GA_PARENT);
7331         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
7332     }
7333     test = GetWindow(parent, GW_OWNER);
7334     ok(!test, "wrong owner %p\n", test);
7335
7336     /* test owner/parent of child1 */
7337     test = GetParent(child1);
7338     ok(test == parent, "wrong parent %p\n", test);
7339     ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
7340     if(pGetAncestor) {
7341         test = pGetAncestor(child1, GA_PARENT);
7342         ok(test == parent, "wrong parent %p\n", test);
7343     }
7344     test = GetWindow(child1, GW_OWNER);
7345     ok(!test, "wrong owner %p\n", test);
7346
7347     /* test owner/parent of child2 */
7348     test = GetParent(child2);
7349     ok(test == parent, "wrong parent %p\n", test);
7350     ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
7351     if(pGetAncestor) {
7352         test = pGetAncestor(child2, GA_PARENT);
7353         ok(test == parent, "wrong parent %p\n", test);
7354     }
7355     test = GetWindow(child2, GW_OWNER);
7356     ok(!test, "wrong owner %p\n", test);
7357
7358     /* test owner/parent of child3 */
7359     test = GetParent(child3);
7360     ok(test == child1, "wrong parent %p\n", test);
7361     ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
7362     if(pGetAncestor) {
7363         test = pGetAncestor(child3, GA_PARENT);
7364         ok(test == child1, "wrong parent %p\n", test);
7365     }
7366     test = GetWindow(child3, GW_OWNER);
7367     ok(!test, "wrong owner %p\n", test);
7368
7369     /* test owner/parent of child4 */
7370     test = GetParent(child4);
7371     ok(test == parent, "wrong parent %p\n", test);
7372     ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
7373     if(pGetAncestor) {
7374         test = pGetAncestor(child4, GA_PARENT);
7375         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
7376     }
7377     test = GetWindow(child4, GW_OWNER);
7378     ok(test == parent, "wrong owner %p\n", test);
7379
7380     flush_sequence();
7381
7382     trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
7383            parent, child1, child2, child3, child4);
7384
7385     SetCapture(child4);
7386     test = GetCapture();
7387     ok(test == child4, "wrong capture window %p\n", test);
7388
7389     test_DestroyWindow_flag = TRUE;
7390     ret = DestroyWindow(parent);
7391     ok( ret, "DestroyWindow() error %d\n", GetLastError());
7392     test_DestroyWindow_flag = FALSE;
7393     ok_sequence(destroy_window_with_children, "destroy window with children", 0);
7394
7395     ok(!IsWindow(parent), "parent still exists\n");
7396     ok(!IsWindow(child1), "child1 still exists\n");
7397     ok(!IsWindow(child2), "child2 still exists\n");
7398     ok(!IsWindow(child3), "child3 still exists\n");
7399     ok(!IsWindow(child4), "child4 still exists\n");
7400
7401     test = GetCapture();
7402     ok(!test, "wrong capture window %p\n", test);
7403 }
7404
7405
7406 static const struct message WmDispatchPaint[] = {
7407     { WM_NCPAINT, sent },
7408     { WM_GETTEXT, sent|defwinproc|optional },
7409     { WM_GETTEXT, sent|defwinproc|optional },
7410     { WM_ERASEBKGND, sent },
7411     { 0 }
7412 };
7413
7414 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7415 {
7416     if (message == WM_PAINT) return 0;
7417     return MsgCheckProcA( hwnd, message, wParam, lParam );
7418 }
7419
7420 static void test_DispatchMessage(void)
7421 {
7422     RECT rect;
7423     MSG msg;
7424     int count;
7425     HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
7426                                100, 100, 200, 200, 0, 0, 0, NULL);
7427     ShowWindow( hwnd, SW_SHOW );
7428     UpdateWindow( hwnd );
7429     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
7430     flush_sequence();
7431     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
7432
7433     SetRect( &rect, -5, -5, 5, 5 );
7434     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
7435     count = 0;
7436     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
7437     {
7438         if (msg.message != WM_PAINT) DispatchMessage( &msg );
7439         else
7440         {
7441             flush_sequence();
7442             DispatchMessage( &msg );
7443             /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
7444             if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
7445             else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
7446             if (++count > 10) break;
7447         }
7448     }
7449     ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
7450
7451     trace("now without DispatchMessage\n");
7452     flush_sequence();
7453     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
7454     count = 0;
7455     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
7456     {
7457         if (msg.message != WM_PAINT) DispatchMessage( &msg );
7458         else
7459         {
7460             HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
7461             flush_sequence();
7462             /* this will send WM_NCCPAINT just like DispatchMessage does */
7463             GetUpdateRgn( hwnd, hrgn, TRUE );
7464             ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
7465             DeleteObject( hrgn );
7466             GetClientRect( hwnd, &rect );
7467             ValidateRect( hwnd, &rect );  /* this will stop WM_PAINTs */
7468             ok( !count, "Got multiple WM_PAINTs\n" );
7469             if (++count > 10) break;
7470         }
7471     }
7472     DestroyWindow(hwnd);
7473 }
7474
7475
7476 static const struct message WmUser[] = {
7477     { WM_USER, sent },
7478     { 0 }
7479 };
7480
7481 struct sendmsg_info
7482 {
7483     HWND  hwnd;
7484     DWORD timeout;
7485     DWORD ret;
7486 };
7487
7488 static DWORD CALLBACK send_msg_thread( LPVOID arg )
7489 {
7490     struct sendmsg_info *info = arg;
7491     info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
7492     if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT, "unexpected error %d\n", GetLastError());
7493     return 0;
7494 }
7495
7496 static void wait_for_thread( HANDLE thread )
7497 {
7498     while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
7499     {
7500         MSG msg;
7501         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage(&msg);
7502     }
7503 }
7504
7505 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7506 {
7507     if (message == WM_USER) Sleep(200);
7508     return MsgCheckProcA( hwnd, message, wParam, lParam );
7509 }
7510
7511 static void test_SendMessageTimeout(void)
7512 {
7513     MSG msg;
7514     HANDLE thread;
7515     struct sendmsg_info info;
7516     DWORD tid;
7517
7518     info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
7519                                100, 100, 200, 200, 0, 0, 0, NULL);
7520     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
7521     flush_sequence();
7522
7523     info.timeout = 1000;
7524     info.ret = 0xdeadbeef;
7525     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
7526     wait_for_thread( thread );
7527     CloseHandle( thread );
7528     ok( info.ret == 1, "SendMessageTimeout failed\n" );
7529     ok_sequence( WmUser, "WmUser", FALSE );
7530
7531     info.timeout = 1;
7532     info.ret = 0xdeadbeef;
7533     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
7534     Sleep(100);  /* SendMessageTimeout should timeout here */
7535     wait_for_thread( thread );
7536     CloseHandle( thread );
7537     ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
7538     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
7539
7540     /* 0 means infinite timeout */
7541     info.timeout = 0;
7542     info.ret = 0xdeadbeef;
7543     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
7544     Sleep(100);
7545     wait_for_thread( thread );
7546     CloseHandle( thread );
7547     ok( info.ret == 1, "SendMessageTimeout failed\n" );
7548     ok_sequence( WmUser, "WmUser", FALSE );
7549
7550     /* timeout is treated as signed despite the prototype */
7551     info.timeout = 0x7fffffff;
7552     info.ret = 0xdeadbeef;
7553     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
7554     Sleep(100);
7555     wait_for_thread( thread );
7556     CloseHandle( thread );
7557     ok( info.ret == 1, "SendMessageTimeout failed\n" );
7558     ok_sequence( WmUser, "WmUser", FALSE );
7559
7560     info.timeout = 0x80000000;
7561     info.ret = 0xdeadbeef;
7562     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
7563     Sleep(100);
7564     wait_for_thread( thread );
7565     CloseHandle( thread );
7566     ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
7567     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
7568
7569     /* now check for timeout during message processing */
7570     SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
7571     info.timeout = 100;
7572     info.ret = 0xdeadbeef;
7573     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
7574     wait_for_thread( thread );
7575     CloseHandle( thread );
7576     /* we should timeout but still get the message */
7577     ok( info.ret == 0, "SendMessageTimeout failed\n" );
7578     ok_sequence( WmUser, "WmUser", FALSE );
7579
7580     DestroyWindow( info.hwnd );
7581 }
7582
7583
7584 /****************** edit message test *************************/
7585 #define ID_EDIT 0x1234
7586 static const struct message sl_edit_setfocus[] =
7587 {
7588     { HCBT_SETFOCUS, hook },
7589     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
7590     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
7591     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7592     { WM_SETFOCUS, sent|wparam, 0 },
7593     { WM_CTLCOLOREDIT, sent|parent },
7594     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7595     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7596     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
7597     { 0 }
7598 };
7599 static const struct message ml_edit_setfocus[] =
7600 {
7601     { HCBT_SETFOCUS, hook },
7602     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
7603     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
7604     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7605     { WM_SETFOCUS, sent|wparam, 0 },
7606     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7607     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7608     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7609     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
7610     { 0 }
7611 };
7612 static const struct message sl_edit_killfocus[] =
7613 {
7614     { HCBT_SETFOCUS, hook },
7615     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7616     { WM_KILLFOCUS, sent|wparam, 0 },
7617     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7618     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7619     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
7620     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
7621     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
7622     { 0 }
7623 };
7624 static const struct message sl_edit_lbutton_dblclk[] =
7625 {
7626     { WM_LBUTTONDBLCLK, sent },
7627     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
7628     { 0 }
7629 };
7630 static const struct message sl_edit_lbutton_down[] =
7631 {
7632     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
7633     { HCBT_SETFOCUS, hook },
7634     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
7635     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
7636     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7637     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
7638     { WM_CTLCOLOREDIT, sent|parent },
7639     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7640     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7641     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7642     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
7643     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
7644     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7645     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7646     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7647     { 0 }
7648 };
7649 static const struct message ml_edit_lbutton_down[] =
7650 {
7651     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
7652     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
7653     { HCBT_SETFOCUS, hook },
7654     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
7655     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
7656     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7657     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
7658     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7659     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7660     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
7661     { 0 }
7662 };
7663 static const struct message sl_edit_lbutton_up[] =
7664 {
7665     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
7666     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7667     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
7668     { WM_CAPTURECHANGED, sent|defwinproc },
7669     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7670     { 0 }
7671 };
7672 static const struct message ml_edit_lbutton_up[] =
7673 {
7674     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
7675     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
7676     { WM_CAPTURECHANGED, sent|defwinproc },
7677     { 0 }
7678 };
7679
7680 static WNDPROC old_edit_proc;
7681
7682 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7683 {
7684     static long defwndproc_counter = 0;
7685     LRESULT ret;
7686     struct message msg;
7687
7688     trace("edit: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
7689
7690     /* explicitly ignore WM_GETICON message */
7691     if (message == WM_GETICON) return 0;
7692
7693     msg.message = message;
7694     msg.flags = sent|wparam|lparam;
7695     if (defwndproc_counter) msg.flags |= defwinproc;
7696     msg.wParam = wParam;
7697     msg.lParam = lParam;
7698     add_message(&msg);
7699
7700     defwndproc_counter++;
7701     ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
7702     defwndproc_counter--;
7703
7704     return ret;
7705 }
7706
7707 static void subclass_edit(void)
7708 {
7709     WNDCLASSA cls;
7710
7711     if (!GetClassInfoA(0, "edit", &cls)) assert(0);
7712
7713     old_edit_proc = cls.lpfnWndProc;
7714
7715     cls.hInstance = GetModuleHandle(0);
7716     cls.lpfnWndProc = edit_hook_proc;
7717     cls.lpszClassName = "my_edit_class";
7718     UnregisterClass(cls.lpszClassName, cls.hInstance);
7719     if (!RegisterClassA(&cls)) assert(0);
7720 }
7721
7722 static void test_edit_messages(void)
7723 {
7724     HWND hwnd, parent;
7725     DWORD dlg_code;
7726
7727     subclass_edit();
7728     log_all_parent_messages++;
7729
7730     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7731                              100, 100, 200, 200, 0, 0, 0, NULL);
7732     ok (parent != 0, "Failed to create parent window\n");
7733
7734     /* test single line edit */
7735     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
7736                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
7737     ok(hwnd != 0, "Failed to create edit window\n");
7738
7739     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
7740     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
7741
7742     ShowWindow(hwnd, SW_SHOW);
7743     UpdateWindow(hwnd);
7744     SetFocus(0);
7745     flush_sequence();
7746
7747     SetFocus(hwnd);
7748     ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
7749
7750     SetFocus(0);
7751     ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
7752
7753     SetFocus(0);
7754     ReleaseCapture();
7755     flush_sequence();
7756
7757     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
7758     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
7759
7760     SetFocus(0);
7761     ReleaseCapture();
7762     flush_sequence();
7763
7764     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
7765     ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
7766
7767     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
7768     ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
7769
7770     DestroyWindow(hwnd);
7771
7772     /* test multiline edit */
7773     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
7774                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
7775     ok(hwnd != 0, "Failed to create edit window\n");
7776
7777     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
7778     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
7779        "wrong dlg_code %08x\n", dlg_code);
7780
7781     ShowWindow(hwnd, SW_SHOW);
7782     UpdateWindow(hwnd);
7783     SetFocus(0);
7784     flush_sequence();
7785
7786     SetFocus(hwnd);
7787     ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
7788
7789     SetFocus(0);
7790     ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
7791
7792     SetFocus(0);
7793     ReleaseCapture();
7794     flush_sequence();
7795
7796     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
7797     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
7798
7799     SetFocus(0);
7800     ReleaseCapture();
7801     flush_sequence();
7802
7803     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
7804     ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
7805
7806     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
7807     ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
7808
7809     DestroyWindow(hwnd);
7810     DestroyWindow(parent);
7811
7812     log_all_parent_messages--;
7813 }
7814
7815 /**************************** End of Edit test ******************************/
7816
7817 static const struct message WmKeyDownSkippedSeq[] =
7818 {
7819     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
7820     { 0 }
7821 };
7822 static const struct message WmKeyUpSkippedSeq[] =
7823 {
7824     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
7825     { 0 }
7826 };
7827
7828 #define EV_START_STOP 0
7829 #define EV_SENDMSG 1
7830 #define EV_ACK 2
7831
7832 struct peekmsg_info
7833 {
7834     HWND  hwnd;
7835     HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
7836 };
7837
7838 static DWORD CALLBACK send_msg_thread_2(void *param)
7839 {
7840     DWORD ret;
7841     struct peekmsg_info *info = param;
7842
7843     trace("thread: waiting for start\n");
7844     WaitForSingleObject(info->hevent[EV_START_STOP], INFINITE);
7845     trace("thread: looping\n");
7846
7847     while (1)
7848     {
7849         ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
7850
7851         switch (ret)
7852         {
7853         case WAIT_OBJECT_0 + EV_START_STOP:
7854             trace("thread: exiting\n");
7855             return 0;
7856
7857         case WAIT_OBJECT_0 + EV_SENDMSG:
7858             trace("thread: sending message\n");
7859             SendNotifyMessageA(info->hwnd, WM_USER, 0, 0);
7860             SetEvent(info->hevent[EV_ACK]);
7861             break;
7862
7863         default:
7864             trace("unexpected return: %04x\n", ret);
7865             assert(0);
7866             break;
7867         }
7868     }
7869     return 0;
7870 }
7871
7872 static void test_PeekMessage(void)
7873 {
7874     MSG msg;
7875     HANDLE hthread;
7876     DWORD tid, qstatus;
7877     UINT qs_all_input = QS_ALLINPUT;
7878     UINT qs_input = QS_INPUT;
7879     BOOL ret;
7880     struct peekmsg_info info;
7881
7882     info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
7883                               100, 100, 200, 200, 0, 0, 0, NULL);
7884     assert(info.hwnd);
7885     ShowWindow(info.hwnd, SW_SHOW);
7886     UpdateWindow(info.hwnd);
7887     SetFocus(info.hwnd);
7888
7889     info.hevent[EV_START_STOP] = CreateEventA(NULL, 0, 0, NULL);
7890     info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
7891     info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
7892
7893     hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
7894     Sleep(100);
7895
7896     trace("signalling to start looping\n");
7897     SetEvent(info.hevent[EV_START_STOP]);
7898
7899     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7900     flush_sequence();
7901
7902     SetLastError(0xdeadbeef);
7903     qstatus = GetQueueStatus(qs_all_input);
7904     if (GetLastError() == ERROR_INVALID_FLAGS)
7905     {
7906         trace("QS_RAWINPUT not supported on this platform\n");
7907         qs_all_input &= ~QS_RAWINPUT;
7908         qs_input &= ~QS_RAWINPUT;
7909     }
7910     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
7911
7912     trace("signalling to send message\n");
7913     SetEvent(info.hevent[EV_SENDMSG]);
7914     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
7915
7916     /* pass invalid QS_xxxx flags */
7917     SetLastError(0xdeadbeef);
7918     qstatus = GetQueueStatus(0xffffffff);
7919     ok(qstatus == 0, "GetQueueStatus should fail: %08x\n", qstatus);
7920     ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
7921
7922     qstatus = GetQueueStatus(qs_all_input);
7923     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
7924        "wrong qstatus %08x\n", qstatus);
7925
7926     msg.message = 0;
7927     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
7928     ok(!ret,
7929        "PeekMessageA should have returned FALSE instead of msg %04x\n",
7930         msg.message);
7931     ok_sequence(WmUser, "WmUser", FALSE);
7932
7933     qstatus = GetQueueStatus(qs_all_input);
7934     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
7935
7936     keybd_event('N', 0, 0, 0);
7937     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7938     qstatus = GetQueueStatus(qs_all_input);
7939     ok(qstatus == MAKELONG(QS_KEY, QS_KEY),
7940        "wrong qstatus %08x\n", qstatus);
7941
7942     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
7943     qstatus = GetQueueStatus(qs_all_input);
7944     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
7945        "wrong qstatus %08x\n", qstatus);
7946
7947     InvalidateRect(info.hwnd, NULL, FALSE);
7948     qstatus = GetQueueStatus(qs_all_input);
7949     ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
7950        "wrong qstatus %08x\n", qstatus);
7951
7952     trace("signalling to send message\n");
7953     SetEvent(info.hevent[EV_SENDMSG]);
7954     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
7955
7956     qstatus = GetQueueStatus(qs_all_input);
7957     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
7958        "wrong qstatus %08x\n", qstatus);
7959
7960     msg.message = 0;
7961     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
7962     ok(!ret,
7963        "PeekMessageA should have returned FALSE instead of msg %04x\n",
7964         msg.message);
7965     ok_sequence(WmUser, "WmUser", FALSE);
7966
7967     qstatus = GetQueueStatus(qs_all_input);
7968     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
7969        "wrong qstatus %08x\n", qstatus);
7970
7971     trace("signalling to send message\n");
7972     SetEvent(info.hevent[EV_SENDMSG]);
7973     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
7974
7975     qstatus = GetQueueStatus(qs_all_input);
7976     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
7977        "wrong qstatus %08x\n", qstatus);
7978
7979     msg.message = 0;
7980     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
7981     ok(!ret,
7982        "PeekMessageA should have returned FALSE instead of msg %04x\n",
7983         msg.message);
7984     ok_sequence(WmUser, "WmUser", FALSE);
7985
7986     qstatus = GetQueueStatus(qs_all_input);
7987     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
7988        "wrong qstatus %08x\n", qstatus);
7989
7990     msg.message = 0;
7991     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
7992     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
7993        "got %d and %04x wParam %08x instead of TRUE and WM_CHAR wParam 'z'\n",
7994        ret, msg.message, msg.wParam);
7995     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
7996
7997     qstatus = GetQueueStatus(qs_all_input);
7998     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
7999        "wrong qstatus %08x\n", qstatus);
8000
8001     msg.message = 0;
8002     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
8003     ok(!ret,
8004        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8005         msg.message);
8006     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8007
8008     qstatus = GetQueueStatus(qs_all_input);
8009     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
8010        "wrong qstatus %08x\n", qstatus);
8011
8012     msg.message = 0;
8013     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
8014     ok(ret && msg.message == WM_PAINT,
8015        "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
8016     DispatchMessageA(&msg);
8017     ok_sequence(WmPaint, "WmPaint", FALSE);
8018
8019     qstatus = GetQueueStatus(qs_all_input);
8020     ok(qstatus == MAKELONG(0, QS_KEY),
8021        "wrong qstatus %08x\n", qstatus);
8022
8023     msg.message = 0;
8024     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
8025     ok(!ret,
8026        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8027         msg.message);
8028     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8029
8030     qstatus = GetQueueStatus(qs_all_input);
8031     ok(qstatus == MAKELONG(0, QS_KEY),
8032        "wrong qstatus %08x\n", qstatus);
8033
8034     trace("signalling to send message\n");
8035     SetEvent(info.hevent[EV_SENDMSG]);
8036     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8037
8038     qstatus = GetQueueStatus(qs_all_input);
8039     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
8040        "wrong qstatus %08x\n", qstatus);
8041
8042     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
8043
8044     qstatus = GetQueueStatus(qs_all_input);
8045     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
8046        "wrong qstatus %08x\n", qstatus);
8047
8048     msg.message = 0;
8049     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
8050     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
8051        "got %d and %04x wParam %08x instead of TRUE and WM_CHAR wParam 'z'\n",
8052        ret, msg.message, msg.wParam);
8053     ok_sequence(WmUser, "WmUser", FALSE);
8054
8055     qstatus = GetQueueStatus(qs_all_input);
8056     ok(qstatus == MAKELONG(0, QS_KEY),
8057        "wrong qstatus %08x\n", qstatus);
8058
8059     msg.message = 0;
8060     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
8061     ok(!ret,
8062        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8063         msg.message);
8064     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8065
8066     qstatus = GetQueueStatus(qs_all_input);
8067     ok(qstatus == MAKELONG(0, QS_KEY),
8068        "wrong qstatus %08x\n", qstatus);
8069
8070     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
8071
8072     qstatus = GetQueueStatus(qs_all_input);
8073     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
8074        "wrong qstatus %08x\n", qstatus);
8075
8076     trace("signalling to send message\n");
8077     SetEvent(info.hevent[EV_SENDMSG]);
8078     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8079
8080     qstatus = GetQueueStatus(qs_all_input);
8081     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
8082        "wrong qstatus %08x\n", qstatus);
8083
8084     msg.message = 0;
8085     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
8086     ok(!ret,
8087        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8088         msg.message);
8089     ok_sequence(WmUser, "WmUser", FALSE);
8090
8091     qstatus = GetQueueStatus(qs_all_input);
8092     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
8093        "wrong qstatus %08x\n", qstatus);
8094
8095     msg.message = 0;
8096     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
8097         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
8098     else /* workaround for a missing QS_RAWINPUT support */
8099         ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
8100     ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
8101        "got %d and %04x wParam %08x instead of TRUE and WM_KEYDOWN wParam 'N'\n",
8102        ret, msg.message, msg.wParam);
8103     ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
8104
8105     qstatus = GetQueueStatus(qs_all_input);
8106     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
8107        "wrong qstatus %08x\n", qstatus);
8108
8109     msg.message = 0;
8110     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
8111         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
8112     else /* workaround for a missing QS_RAWINPUT support */
8113         ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
8114     ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
8115        "got %d and %04x wParam %08x instead of TRUE and WM_KEYUP wParam 'N'\n",
8116        ret, msg.message, msg.wParam);
8117     ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
8118
8119     qstatus = GetQueueStatus(qs_all_input);
8120     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
8121        "wrong qstatus %08x\n", qstatus);
8122
8123     msg.message = 0;
8124     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
8125     ok(!ret,
8126        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8127         msg.message);
8128     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8129
8130     qstatus = GetQueueStatus(qs_all_input);
8131     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
8132        "wrong qstatus %08x\n", qstatus);
8133
8134     msg.message = 0;
8135     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8136     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
8137        "got %d and %04x wParam %08x instead of TRUE and WM_CHAR wParam 'z'\n",
8138        ret, msg.message, msg.wParam);
8139     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8140
8141     qstatus = GetQueueStatus(qs_all_input);
8142     ok(qstatus == 0,
8143        "wrong qstatus %08x\n", qstatus);
8144
8145     msg.message = 0;
8146     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8147     ok(!ret,
8148        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8149         msg.message);
8150     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8151
8152     qstatus = GetQueueStatus(qs_all_input);
8153     ok(qstatus == 0,
8154        "wrong qstatus %08x\n", qstatus);
8155
8156     /* test whether presence of the quit flag in the queue affects
8157      * the queue state
8158      */
8159     PostQuitMessage(0x1234abcd);
8160
8161     qstatus = GetQueueStatus(qs_all_input);
8162     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
8163        "wrong qstatus %08x\n", qstatus);
8164
8165     PostMessageA(info.hwnd, WM_USER, 0, 0);
8166
8167     qstatus = GetQueueStatus(qs_all_input);
8168     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
8169        "wrong qstatus %08x\n", qstatus);
8170
8171     msg.message = 0;
8172     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8173     ok(ret && msg.message == WM_USER,
8174        "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
8175     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8176
8177     qstatus = GetQueueStatus(qs_all_input);
8178     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
8179        "wrong qstatus %08x\n", qstatus);
8180
8181     msg.message = 0;
8182     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8183     ok(ret && msg.message == WM_QUIT,
8184        "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
8185     ok(msg.wParam == 0x1234abcd, "got wParam %08x instead of 0x1234abcd\n", msg.wParam);
8186     ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
8187     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8188
8189     qstatus = GetQueueStatus(qs_all_input);
8190 todo_wine {
8191     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
8192        "wrong qstatus %08x\n", qstatus);
8193 }
8194
8195     msg.message = 0;
8196     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8197     ok(!ret,
8198        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8199         msg.message);
8200     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8201
8202     qstatus = GetQueueStatus(qs_all_input);
8203     ok(qstatus == 0,
8204        "wrong qstatus %08x\n", qstatus);
8205
8206     trace("signalling to exit\n");
8207     SetEvent(info.hevent[EV_START_STOP]);
8208
8209     WaitForSingleObject(hthread, INFINITE);
8210
8211     CloseHandle(hthread);
8212     CloseHandle(info.hevent[0]);
8213     CloseHandle(info.hevent[1]);
8214     CloseHandle(info.hevent[2]);
8215
8216     DestroyWindow(info.hwnd);
8217 }
8218
8219
8220 static void test_quit_message(void)
8221 {
8222     MSG msg;
8223     BOOL ret;
8224
8225     /* test using PostQuitMessage */
8226     PostQuitMessage(0xbeef);
8227
8228     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
8229     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
8230     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
8231     ok(msg.wParam == 0xbeef, "wParam was 0x%x instead of 0xbeef\n", msg.wParam);
8232
8233     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
8234     ok(ret, "PostMessage failed with error %d\n", GetLastError());
8235
8236     ret = GetMessage(&msg, NULL, 0, 0);
8237     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
8238     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
8239
8240     /* note: WM_QUIT message received after WM_USER message */
8241     ret = GetMessage(&msg, NULL, 0, 0);
8242     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
8243     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
8244     ok(msg.wParam == 0xbeef, "wParam was 0x%x instead of 0xbeef\n", msg.wParam);
8245
8246     ret = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
8247     ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
8248
8249     /* now test with PostThreadMessage - different behaviour! */
8250     PostThreadMessage(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
8251
8252     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
8253     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
8254     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
8255     ok(msg.wParam == 0xdead, "wParam was 0x%x instead of 0xdead\n", msg.wParam);
8256
8257     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
8258     ok(ret, "PostMessage failed with error %d\n", GetLastError());
8259
8260     /* note: we receive the WM_QUIT message first this time */
8261     ret = GetMessage(&msg, NULL, 0, 0);
8262     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
8263     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
8264     ok(msg.wParam == 0xdead, "wParam was 0x%x instead of 0xdead\n", msg.wParam);
8265
8266     ret = GetMessage(&msg, NULL, 0, 0);
8267     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
8268     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
8269 }
8270
8271 static const struct message WmMouseHoverSeq[] = {
8272     { WM_TIMER, sent|optional }, /* XP sends it */
8273     { WM_SYSTIMER, sent },
8274     { WM_MOUSEHOVER, sent|wparam, 0 },
8275     { 0 }
8276 };
8277
8278 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
8279 {
8280     MSG msg;
8281     DWORD start_ticks, end_ticks;
8282
8283     start_ticks = GetTickCount();
8284     /* add some deviation (5%) to cover not expected delays */
8285     start_ticks += timeout / 20;
8286
8287     do
8288     {
8289         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
8290         {
8291             /* Timer proc messages are not dispatched to the window proc,
8292              * and therefore not logged.
8293              */
8294             if (msg.message == WM_TIMER || msg.message == WM_SYSTIMER)
8295             {
8296                 struct message s_msg;
8297
8298                 s_msg.message = msg.message;
8299                 s_msg.flags = sent|wparam|lparam;
8300                 s_msg.wParam = msg.wParam;
8301                 s_msg.lParam = msg.lParam;
8302                 add_message(&s_msg);
8303             }
8304             DispatchMessage(&msg);
8305         }
8306
8307         end_ticks = GetTickCount();
8308
8309         /* inject WM_MOUSEMOVE to see how it changes tracking */
8310         if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
8311         {
8312             mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8313             mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8314
8315             inject_mouse_move = FALSE;
8316         }
8317     } while (start_ticks + timeout >= end_ticks);
8318 }
8319
8320 static void test_TrackMouseEvent(void)
8321 {
8322     MSG msg;
8323     TRACKMOUSEEVENT tme;
8324     BOOL ret;
8325     HWND hwnd, hchild;
8326     RECT rc_parent, rc_child;
8327     UINT default_hover_time, hover_width = 0, hover_height = 0;
8328
8329 #define track_hover(track_hwnd, track_hover_time) \
8330     tme.cbSize = sizeof(tme); \
8331     tme.dwFlags = TME_HOVER; \
8332     tme.hwndTrack = track_hwnd; \
8333     tme.dwHoverTime = track_hover_time; \
8334     SetLastError(0xdeadbeef); \
8335     ret = TrackMouseEvent(&tme); \
8336     ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
8337
8338 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
8339     tme.cbSize = sizeof(tme); \
8340     tme.dwFlags = TME_QUERY; \
8341     tme.hwndTrack = (HWND)0xdeadbeef; \
8342     tme.dwHoverTime = 0xdeadbeef; \
8343     SetLastError(0xdeadbeef); \
8344     ret = TrackMouseEvent(&tme); \
8345     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
8346     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
8347     ok(tme.dwFlags == (expected_track_flags), \
8348        "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
8349     ok(tme.hwndTrack == (expected_track_hwnd), \
8350        "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
8351     ok(tme.dwHoverTime == (expected_hover_time), \
8352        "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
8353
8354 #define track_hover_cancel(track_hwnd) \
8355     tme.cbSize = sizeof(tme); \
8356     tme.dwFlags = TME_HOVER | TME_CANCEL; \
8357     tme.hwndTrack = track_hwnd; \
8358     tme.dwHoverTime = 0xdeadbeef; \
8359     SetLastError(0xdeadbeef); \
8360     ret = TrackMouseEvent(&tme); \
8361     ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
8362
8363     default_hover_time = 0xdeadbeef;
8364     SetLastError(0xdeadbeef);
8365     ret = SystemParametersInfo(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
8366     ok(ret, "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
8367     if (!ret) default_hover_time = 400;
8368     trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
8369
8370     SetLastError(0xdeadbeef);
8371     ret = SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
8372     ok(ret, "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
8373     if (!ret) hover_width = 4;
8374     SetLastError(0xdeadbeef);
8375     ret = SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
8376     ok(ret, "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
8377     if (!ret) hover_height = 4;
8378     trace("hover rect is %u x %d\n", hover_width, hover_height);
8379
8380     hwnd = CreateWindowEx(0, "TestWindowClass", NULL,
8381                           WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8382                           CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
8383                           NULL, NULL, 0);
8384     assert(hwnd);
8385
8386     hchild = CreateWindowEx(0, "TestWindowClass", NULL,
8387                           WS_CHILD | WS_BORDER | WS_VISIBLE,
8388                           50, 50, 200, 200, hwnd,
8389                           NULL, NULL, 0);
8390     assert(hchild);
8391
8392     flush_events();
8393     flush_sequence();
8394
8395     tme.cbSize = 0;
8396     tme.dwFlags = TME_QUERY;
8397     tme.hwndTrack = (HWND)0xdeadbeef;
8398     tme.dwHoverTime = 0xdeadbeef;
8399     SetLastError(0xdeadbeef);
8400     ret = TrackMouseEvent(&tme);
8401     ok(!ret, "TrackMouseEvent should fail\n");
8402     ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
8403
8404     tme.cbSize = sizeof(tme);
8405     tme.dwFlags = TME_HOVER;
8406     tme.hwndTrack = (HWND)0xdeadbeef;
8407     tme.dwHoverTime = 0xdeadbeef;
8408     SetLastError(0xdeadbeef);
8409     ret = TrackMouseEvent(&tme);
8410     ok(!ret, "TrackMouseEvent should fail\n");
8411     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "not expected error %d\n", GetLastError());
8412
8413     tme.cbSize = sizeof(tme);
8414     tme.dwFlags = TME_HOVER | TME_CANCEL;
8415     tme.hwndTrack = (HWND)0xdeadbeef;
8416     tme.dwHoverTime = 0xdeadbeef;
8417     SetLastError(0xdeadbeef);
8418     ret = TrackMouseEvent(&tme);
8419     ok(!ret, "TrackMouseEvent should fail\n");
8420     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "not expected error %d\n", GetLastError());
8421
8422     GetWindowRect(hwnd, &rc_parent);
8423     GetWindowRect(hchild, &rc_child);
8424     SetCursorPos(rc_child.left - 10, rc_child.top - 10);
8425
8426     /* Process messages so that the system updates its internal current
8427      * window and hittest, otherwise TrackMouseEvent calls don't have any
8428      * effect.
8429      */
8430     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
8431     flush_sequence();
8432
8433     track_query(0, NULL, 0);
8434     track_hover(hchild, 0);
8435     track_query(0, NULL, 0);
8436
8437     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
8438     flush_sequence();
8439
8440     track_hover(hwnd, 0);
8441     track_query(TME_HOVER, hwnd, default_hover_time);
8442
8443     pump_msg_loop_timeout(default_hover_time, FALSE);
8444     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
8445
8446     track_query(0, NULL, 0);
8447
8448     track_hover(hwnd, HOVER_DEFAULT);
8449     track_query(TME_HOVER, hwnd, default_hover_time);
8450
8451     Sleep(default_hover_time / 2);
8452     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8453     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8454
8455     track_query(TME_HOVER, hwnd, default_hover_time);
8456
8457     pump_msg_loop_timeout(default_hover_time / 2, FALSE);
8458     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
8459
8460     track_query(0, NULL, 0);
8461
8462     track_hover(hwnd, HOVER_DEFAULT);
8463     track_query(TME_HOVER, hwnd, default_hover_time);
8464
8465     pump_msg_loop_timeout(default_hover_time, TRUE);
8466     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
8467
8468     track_query(0, NULL, 0);
8469
8470     track_hover(hwnd, HOVER_DEFAULT);
8471     track_query(TME_HOVER, hwnd, default_hover_time);
8472     track_hover_cancel(hwnd);
8473
8474     DestroyWindow(hwnd);
8475
8476 #undef track_hover
8477 #undef track_query
8478 #undef track_hover_cancel
8479 }
8480
8481
8482 static const struct message WmSetWindowRgn[] = {
8483     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
8484     { WM_NCCALCSIZE, sent|wparam, 1 },
8485     { WM_NCPAINT, sent }, /* wparam != 1 */
8486     { WM_GETTEXT, sent|defwinproc|optional },
8487     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
8488     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
8489     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
8490     { 0 }
8491 };
8492
8493 static const struct message WmSetWindowRgn_no_redraw[] = {
8494     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
8495     { WM_NCCALCSIZE, sent|wparam, 1 },
8496     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
8497     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
8498     { 0 }
8499 };
8500
8501 static const struct message WmSetWindowRgn_clear[] = {
8502     { 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 */
8503     { WM_NCCALCSIZE, sent|wparam, 1 },
8504     { WM_NCPAINT, sent }, /* wparam != 1 */
8505     { WM_GETTEXT, sent|defwinproc|optional },
8506     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
8507     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
8508     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
8509     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
8510     { WM_GETTEXT, sent|defwinproc|optional },
8511     { WM_ERASEBKGND, sent|optional },
8512     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
8513     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
8514     { 0 }
8515 };
8516
8517 static void test_SetWindowRgn(void)
8518 {
8519     HRGN hrgn;
8520     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
8521                                 100, 100, 200, 200, 0, 0, 0, NULL);
8522     ok( hwnd != 0, "Failed to create overlapped window\n" );
8523
8524     ShowWindow( hwnd, SW_SHOW );
8525     UpdateWindow( hwnd );
8526     flush_events();
8527     flush_sequence();
8528
8529     trace("testing SetWindowRgn\n");
8530     hrgn = CreateRectRgn( 0, 0, 150, 150 );
8531     SetWindowRgn( hwnd, hrgn, TRUE );
8532     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
8533
8534     hrgn = CreateRectRgn( 30, 30, 160, 160 );
8535     SetWindowRgn( hwnd, hrgn, FALSE );
8536     ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
8537
8538     hrgn = CreateRectRgn( 0, 0, 180, 180 );
8539     SetWindowRgn( hwnd, hrgn, TRUE );
8540     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
8541
8542     SetWindowRgn( hwnd, 0, TRUE );
8543     ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
8544
8545     DestroyWindow( hwnd );
8546 }
8547
8548 /*************************** ShowWindow() test ******************************/
8549 static const struct message WmShowNormal[] = {
8550     { WM_SHOWWINDOW, sent|wparam, 1 },
8551     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
8552     { HCBT_ACTIVATE, hook },
8553     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
8554     { HCBT_SETFOCUS, hook },
8555     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
8556     { 0 }
8557 };
8558 static const struct message WmShow[] = {
8559     { WM_SHOWWINDOW, sent|wparam, 1 },
8560     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
8561     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
8562     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
8563     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
8564     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
8565     { 0 }
8566 };
8567 static const struct message WmShowNoActivate_1[] = {
8568     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
8569     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|0x8000 },
8570     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|0x8000 },
8571     { WM_MOVE, sent|defwinproc },
8572     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
8573     { 0 }
8574 };
8575 static const struct message WmShowNoActivate_2[] = {
8576     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
8577     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8578     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8579     { WM_MOVE, sent|defwinproc },
8580     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
8581     { HCBT_SETFOCUS, hook },
8582     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
8583     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
8584     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
8585     { 0 }
8586 };
8587 static const struct message WmShowNA_1[] = {
8588     { WM_SHOWWINDOW, sent|wparam, 1 },
8589     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
8590     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
8591     { 0 }
8592 };
8593 static const struct message WmShowNA_2[] = {
8594     { WM_SHOWWINDOW, sent|wparam, 1 },
8595     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
8596     { 0 }
8597 };
8598 static const struct message WmRestore_1[] = {
8599     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
8600     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8601     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
8602     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
8603     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
8604     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8605     { WM_MOVE, sent|defwinproc },
8606     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
8607     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
8608     { 0 }
8609 };
8610 static const struct message WmRestore_2[] = {
8611     { WM_SHOWWINDOW, sent|wparam, 1 },
8612     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
8613     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
8614     { 0 }
8615 };
8616 static const struct message WmRestore_3[] = {
8617     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
8618     { WM_GETMINMAXINFO, sent },
8619     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8620     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
8621     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
8622     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
8623     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8624     { WM_MOVE, sent|defwinproc },
8625     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
8626     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
8627     { 0 }
8628 };
8629 static const struct message WmRestore_4[] = {
8630     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
8631     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
8632     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|0x8000 },
8633     { WM_MOVE, sent|defwinproc },
8634     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
8635     { 0 }
8636 };
8637 static const struct message WmRestore_5[] = {
8638     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
8639     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
8640     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|0x8000 },
8641     { WM_MOVE, sent|defwinproc },
8642     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
8643     { 0 }
8644 };
8645 static const struct message WmHide_1[] = {
8646     { WM_SHOWWINDOW, sent|wparam, 0 },
8647     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
8648     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
8649     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
8650     { 0 }
8651 };
8652 static const struct message WmHide_2[] = {
8653     { WM_SHOWWINDOW, sent|wparam, 0 },
8654     { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
8655     { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
8656     { 0 }
8657 };
8658 static const struct message WmHide_3[] = {
8659     { WM_SHOWWINDOW, sent|wparam, 0 },
8660     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
8661     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
8662     { HCBT_SETFOCUS, hook },
8663     { 0 }
8664 };
8665 static const struct message WmShowMinimized_1[] = {
8666     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
8667     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8668     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
8669     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
8670     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8671     { WM_MOVE, sent|defwinproc },
8672     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
8673     { 0 }
8674 };
8675 static const struct message WmMinimize_1[] = {
8676     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
8677     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
8678     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8679     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8680     { WM_MOVE, sent|defwinproc },
8681     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
8682     { 0 }
8683 };
8684 static const struct message WmMinimize_2[] = {
8685     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
8686     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8687     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8688     { WM_MOVE, sent|defwinproc },
8689     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
8690     { 0 }
8691 };
8692 static const struct message WmMinimize_3[] = {
8693     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
8694     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8695     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8696     { WM_MOVE, sent|defwinproc },
8697     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
8698     { 0 }
8699 };
8700 static const struct message WmShowMinNoActivate[] = {
8701     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
8702     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
8703     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
8704     { 0 }
8705 };
8706 static const struct message WmMinMax_1[] = {
8707     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
8708     { 0 }
8709 };
8710 static const struct message WmMinMax_2[] = {
8711     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
8712     { 0 }
8713 };
8714 static const struct message WmMinMax_3[] = {
8715     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
8716     { 0 }
8717 };
8718 static const struct message WmMinMax_4[] = {
8719     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
8720     { 0 }
8721 };
8722 static const struct message WmShowMaximized_1[] = {
8723     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
8724     { WM_GETMINMAXINFO, sent },
8725     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8726     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
8727     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
8728     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
8729     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8730     { WM_MOVE, sent|defwinproc },
8731     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
8732     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
8733     { 0 }
8734 };
8735 static const struct message WmShowMaximized_2[] = {
8736     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
8737     { WM_GETMINMAXINFO, sent },
8738     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
8739     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
8740     { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
8741     { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
8742     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8743     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8744     { WM_MOVE, sent|defwinproc },
8745     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
8746     { HCBT_SETFOCUS, hook },
8747     { 0 }
8748 };
8749 static const struct message WmShowMaximized_3[] = {
8750     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
8751     { WM_GETMINMAXINFO, sent },
8752     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
8753     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|0x8000 },
8754     { WM_MOVE, sent|defwinproc },
8755     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
8756     { 0 }
8757 };
8758
8759 static void test_ShowWindow(void)
8760 {
8761     /* ShowWindow commands in random order */
8762     static const struct
8763     {
8764         INT cmd; /* ShowWindow command */
8765         LPARAM ret; /* ShowWindow return value */
8766         DWORD style; /* window style after the command */
8767         const struct message *msg; /* message sequence the command produces */
8768         BOOL todo_msg; /* message sequence doesn't match what Wine does */
8769     } sw[] =
8770     {
8771 /*  1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal, FALSE },
8772 /*  2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
8773 /*  3 */ { SW_HIDE, TRUE, 0, WmHide_1, FALSE },
8774 /*  4 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
8775 /*  5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1, FALSE },
8776 /*  6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1, FALSE },
8777 /*  7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1, FALSE },
8778 /*  8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
8779 /*  9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1, FALSE },
8780 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2, FALSE },
8781 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1, FALSE },
8782 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq, FALSE },
8783 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1, FALSE },
8784 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
8785 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2, FALSE },
8786 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
8787 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow, FALSE },
8788 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
8789 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1, TRUE },
8790 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
8791 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
8792 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate, TRUE },
8793 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4, FALSE },
8794 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
8795 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
8796 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1, FALSE },
8797 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2, FALSE },
8798 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
8799 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
8800 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1, FALSE },
8801 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
8802 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3, TRUE },
8803 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
8804 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, TRUE }, /* what does this mean?! */
8805 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, TRUE },
8806 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
8807 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2, FALSE },
8808 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
8809 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
8810 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2, TRUE },
8811 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
8812 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2, TRUE },
8813 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2, FALSE },
8814 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1, TRUE },
8815 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
8816 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3, FALSE },
8817 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4, FALSE },
8818 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3, FALSE },
8819 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq, FALSE },
8820 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5, FALSE },
8821 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
8822 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1, FALSE },
8823 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
8824 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3, TRUE },
8825 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
8826 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2, FALSE },
8827 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq, FALSE }
8828     };
8829     HWND hwnd;
8830     DWORD style;
8831     LPARAM ret;
8832     INT i;
8833
8834 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
8835     hwnd = CreateWindowEx(0, "ShowWindowClass", NULL, WS_BASE,
8836                           120, 120, 90, 90,
8837                           0, 0, 0, NULL);
8838     assert(hwnd);
8839
8840     style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
8841     ok(style == 0, "expected style 0, got %08x\n", style);
8842
8843     flush_events();
8844     flush_sequence();
8845
8846     for (i = 0; i < sizeof(sw)/sizeof(sw[0]); i++)
8847     {
8848         static const char * const sw_cmd_name[13] =
8849         {
8850             "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
8851             "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
8852             "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
8853             "SW_NORMALNA" /* 0xCC */
8854         };
8855         char comment[64];
8856         INT idx; /* index into the above array of names */
8857
8858         idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
8859
8860         style = GetWindowLong(hwnd, GWL_STYLE);
8861         trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
8862         ret = ShowWindow(hwnd, sw[i].cmd);
8863         ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
8864         style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
8865         ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
8866
8867         sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
8868         ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
8869
8870         flush_events();
8871         flush_sequence();
8872     }
8873
8874     DestroyWindow(hwnd);
8875 }
8876
8877 static const struct message WmDefDlgSetFocus_1[] = {
8878     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
8879     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
8880     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
8881     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
8882     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
8883     { HCBT_SETFOCUS, hook },
8884     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
8885     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8886     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8887     { WM_SETFOCUS, sent|wparam, 0 },
8888     { WM_CTLCOLOREDIT, sent },
8889     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8890     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8891     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8892     { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
8893     { 0 }
8894 };
8895 static const struct message WmDefDlgSetFocus_2[] = {
8896     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
8897     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
8898     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
8899     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
8900     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
8901     { 0 }
8902 };
8903
8904 static void test_dialog_messages(void)
8905 {
8906     HWND hdlg, hedit1, hedit2, hfocus;
8907     LRESULT ret;
8908
8909 #define set_selection(hctl, start, end) \
8910     ret = SendMessage(hctl, EM_SETSEL, start, end); \
8911     ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
8912
8913 #define check_selection(hctl, start, end) \
8914     ret = SendMessage(hctl, EM_GETSEL, 0, 0); \
8915     ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
8916
8917     subclass_edit();
8918
8919     hdlg = CreateWindowEx(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
8920                           WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
8921                           0, 0, 100, 100, 0, 0, 0, NULL);
8922     ok(hdlg != 0, "Failed to create custom dialog window\n");
8923
8924     hedit1 = CreateWindowEx(0, "my_edit_class", NULL,
8925                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
8926                            0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
8927     ok(hedit1 != 0, "Failed to create edit control\n");
8928     hedit2 = CreateWindowEx(0, "my_edit_class", NULL,
8929                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
8930                            0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
8931     ok(hedit2 != 0, "Failed to create edit control\n");
8932
8933     SendMessage(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
8934     SendMessage(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
8935
8936     hfocus = GetFocus();
8937     ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
8938
8939     SetFocus(hedit2);
8940     hfocus = GetFocus();
8941     ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
8942
8943     check_selection(hedit1, 0, 0);
8944     check_selection(hedit2, 0, 0);
8945
8946     set_selection(hedit2, 0, -1);
8947     check_selection(hedit2, 0, 3);
8948
8949     SetFocus(0);
8950     hfocus = GetFocus();
8951     ok(hfocus == 0, "wrong focus %p\n", hfocus);
8952
8953     flush_sequence();
8954     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
8955     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
8956     ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
8957
8958     hfocus = GetFocus();
8959     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
8960
8961     check_selection(hedit1, 0, 5);
8962     check_selection(hedit2, 0, 3);
8963
8964     flush_sequence();
8965     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
8966     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
8967     ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
8968
8969     hfocus = GetFocus();
8970     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
8971
8972     check_selection(hedit1, 0, 5);
8973     check_selection(hedit2, 0, 3);
8974
8975     EndDialog(hdlg, 0);
8976
8977 #undef set_selection
8978 #undef check_selection
8979 }
8980
8981 static void test_nullCallback(void)
8982 {
8983     HWND hwnd;
8984     MSG msg;
8985
8986     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
8987                            100, 100, 200, 200, 0, 0, 0, NULL);
8988     ok (hwnd != 0, "Failed to create overlapped window\n");
8989
8990     SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
8991     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
8992     DestroyWindow(hwnd);
8993 }
8994
8995 START_TEST(msg)
8996 {
8997     BOOL ret;
8998     HMODULE user32 = GetModuleHandleA("user32.dll");
8999     FARPROC pSetWinEventHook = GetProcAddress(user32, "SetWinEventHook");
9000     FARPROC pUnhookWinEvent = GetProcAddress(user32, "UnhookWinEvent");
9001     FARPROC pIsWinEventHookInstalled = 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
9002     pGetAncestor = (void*) GetProcAddress(user32, "GetAncestor");
9003
9004     if (!RegisterWindowClasses()) assert(0);
9005
9006     if (pSetWinEventHook)
9007     {
9008         hEvent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
9009                                                       GetModuleHandleA(0),
9010                                                       win_event_proc,
9011                                                       0,
9012                                                       GetCurrentThreadId(),
9013                                                       WINEVENT_INCONTEXT);
9014         assert(hEvent_hook);
9015
9016         if (pIsWinEventHookInstalled)
9017         {
9018             UINT event;
9019             for (event = EVENT_MIN; event <= EVENT_MAX; event++)
9020                 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
9021         }
9022     }
9023
9024     cbt_hook_thread_id = GetCurrentThreadId();
9025     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
9026     assert(hCBT_hook);
9027
9028     test_winevents();
9029
9030     /* Fix message sequences before removing 4 lines below */
9031 #if 1
9032     if (pUnhookWinEvent && hEvent_hook)
9033     {
9034         ret = pUnhookWinEvent(hEvent_hook);
9035         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
9036         pUnhookWinEvent = 0;
9037     }
9038     hEvent_hook = 0;
9039 #endif
9040
9041     test_ShowWindow();
9042     test_PeekMessage();
9043     test_scrollwindowex();
9044     test_messages();
9045     test_showwindow();
9046     invisible_parent_tests();
9047     test_mdi_messages();
9048     test_button_messages();
9049     test_static_messages();
9050     test_paint_messages();
9051     test_interthread_messages();
9052     test_message_conversion();
9053     test_accelerators();
9054     test_timers();
9055     test_set_hook();
9056     test_DestroyWindow();
9057     test_DispatchMessage();
9058     test_SendMessageTimeout();
9059     test_edit_messages();
9060     test_quit_message();
9061     test_TrackMouseEvent();
9062     test_SetWindowRgn();
9063     test_sys_menu();
9064     test_dialog_messages();
9065     test_nullCallback();
9066
9067     UnhookWindowsHookEx(hCBT_hook);
9068     if (pUnhookWinEvent)
9069     {
9070         ret = pUnhookWinEvent(hEvent_hook);
9071         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
9072         SetLastError(0xdeadbeef);
9073         ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
9074         ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
9075            GetLastError() == 0xdeadbeef, /* Win9x */
9076            "unexpected error %d\n", GetLastError());
9077     }
9078 }