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