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