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