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