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