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