user32/tests: Allow WM_MOUSEACTIVATE in the mouse hover test for compatibility with...
[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 void dump_winpos_flags(UINT flags);
58
59 static const WCHAR testWindowClassW[] =
60 { 'T','e','s','t','W','i','n','d','o','w','C','l','a','s','s','W',0 };
61
62 /*
63 FIXME: add tests for these
64 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
65  WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
66  WS_THICKFRAME: thick border
67  WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
68  WS_BORDER (default for overlapped windows): single black border
69  none (default for child (and popup?) windows): no border
70 */
71
72 typedef enum {
73     sent=0x1,
74     posted=0x2,
75     parent=0x4,
76     wparam=0x8,
77     lparam=0x10,
78     defwinproc=0x20,
79     beginpaint=0x40,
80     optional=0x80,
81     hook=0x100,
82     winevent_hook=0x200
83 } msg_flags_t;
84
85 struct message {
86     UINT message;          /* the WM_* code */
87     msg_flags_t flags;     /* message props */
88     WPARAM wParam;         /* expected value of wParam */
89     LPARAM lParam;         /* expected value of lParam */
90 };
91
92 /* Empty message sequence */
93 static const struct message WmEmptySeq[] =
94 {
95     { 0 }
96 };
97 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
98 static const struct message WmCreateOverlappedSeq[] = {
99     { HCBT_CREATEWND, hook },
100     { WM_GETMINMAXINFO, sent },
101     { WM_NCCREATE, sent },
102     { WM_NCCALCSIZE, sent|wparam, 0 },
103     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
104     { WM_CREATE, sent },
105     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
106     { 0 }
107 };
108 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
109  * for a not visible overlapped window.
110  */
111 static const struct message WmSWP_ShowOverlappedSeq[] = {
112     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
113     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
114     { WM_NCPAINT, sent|wparam|optional, 1 },
115     { WM_GETTEXT, sent|defwinproc|optional },
116     { WM_ERASEBKGND, sent|optional },
117     { HCBT_ACTIVATE, hook },
118     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
119     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
120     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
121     { WM_ACTIVATEAPP, sent|wparam, 1 },
122     { WM_NCACTIVATE, sent|wparam, 1 },
123     { WM_GETTEXT, sent|defwinproc|optional },
124     { WM_ACTIVATE, sent|wparam, 1 },
125     { HCBT_SETFOCUS, hook },
126     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
127     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
128     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
129     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
130     { WM_NCPAINT, sent|wparam|optional, 1 },
131     { WM_GETTEXT, sent|defwinproc|optional },
132     { WM_ERASEBKGND, sent|optional },
133     /* Win9x adds SWP_NOZORDER below */
134     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
135     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
136     { WM_NCPAINT, sent|wparam|optional, 1 },
137     { WM_ERASEBKGND, sent|optional },
138     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
139     { 0 }
140 };
141 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
142  * for a visible overlapped window.
143  */
144 static const struct message WmSWP_HideOverlappedSeq[] = {
145     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
146     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
147     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
148     { 0 }
149 };
150
151 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
152  * for a visible overlapped window.
153  */
154 static const struct message WmSWP_ResizeSeq[] = {
155     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
156     { WM_GETMINMAXINFO, sent|defwinproc },
157     { WM_NCCALCSIZE, sent|wparam, TRUE },
158     { WM_NCPAINT, sent|optional },
159     { WM_GETTEXT, sent|defwinproc|optional },
160     { WM_ERASEBKGND, sent|optional },
161     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
162     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
163     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
164     { WM_NCPAINT, sent|optional },
165     { WM_GETTEXT, sent|defwinproc|optional },
166     { WM_ERASEBKGND, sent|optional },
167     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
168     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
169     { 0 }
170 };
171
172 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
173  * for a visible popup window.
174  */
175 static const struct message WmSWP_ResizePopupSeq[] = {
176     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
177     { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* Win9x */
178     { WM_NCCALCSIZE, sent|wparam, TRUE },
179     { WM_NCPAINT, sent|optional },
180     { WM_GETTEXT, sent|defwinproc|optional },
181     { WM_ERASEBKGND, sent|optional },
182     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
183     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
184     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
185     { WM_NCPAINT, sent|optional },
186     { WM_GETTEXT, sent|defwinproc|optional },
187     { WM_ERASEBKGND, sent|optional },
188     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
189     { 0 }
190 };
191
192 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE)
193  * for a visible overlapped window.
194  */
195 static const struct message WmSWP_MoveSeq[] = {
196     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE },
197     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
198     { WM_MOVE, sent|defwinproc|wparam, 0 },
199     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
200     { 0 }
201 };
202 /* Resize with SetWindowPos(SWP_NOZORDER)
203  * for a visible overlapped window
204  * SWP_NOZORDER is stripped by the logging code
205  */
206 static const struct message WmSWP_ResizeNoZOrder[] = {
207     { WM_WINDOWPOSCHANGING, sent|wparam, 0/*SWP_NOZORDER*/ },
208     { WM_GETMINMAXINFO, sent|defwinproc },
209     { WM_NCCALCSIZE, sent|wparam, 1 },
210     { WM_NCPAINT, sent },
211     { WM_GETTEXT, sent|defwinproc|optional },
212     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
213     { WM_WINDOWPOSCHANGED, sent|wparam, /*SWP_NOZORDER|*/SWP_NOMOVE|SWP_NOCLIENTMOVE },
214     { WM_SIZE, sent|defwinproc|wparam, 0 },
215     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
216     { WM_NCPAINT, sent|optional }, /* Win9x doesn't send it */
217     { WM_GETTEXT, sent|defwinproc|optional }, /* Win9x doesn't send it */
218     { WM_ERASEBKGND, sent|optional }, /* Win9x doesn't send it */
219     { 0 }
220 };
221
222 /* Switch visible mdi children */
223 static const struct message WmSwitchChild[] = {
224     /* Switch MDI child */
225     { WM_MDIACTIVATE, sent },/* in the MDI client */
226     { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 1st MDI child */
227     { WM_CHILDACTIVATE, sent },/* in the 1st MDI child */
228     /* Deactivate 2nd MDI child */
229     { WM_NCACTIVATE, sent|defwinproc|optional },/* in the 2nd MDI child */
230     { WM_MDIACTIVATE, sent|defwinproc|optional },/* in the 2nd MDI child */
231     { WM_CREATE, hook },
232     /* Preparing for maximize and maximaze the 1st MDI child */
233     { WM_GETMINMAXINFO, sent|defwinproc|optional },/* in the 1st MDI child */
234     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_FRAMECHANGED|SWP_STATECHANGED },/* in the 1st MDI child */
235     { WM_GETMINMAXINFO, sent|defwinproc|optional },/* in the 1st MDI child */
236     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },/* in the 1st MDI child */
237     { WM_CHILDACTIVATE, sent|defwinproc|optional },/* in the 1st MDI child */
238     { WM_WINDOWPOSCHANGED, sent|defwinproc|optional },/* in the 1st MDI child */
239     { WM_MOVE, sent|defwinproc|optional },/* in the 1st MDI child */
240     { WM_SIZE, sent|defwinproc|optional },/* in the 1st MDI child */
241     /* Lock redraw 2nd MDI child */
242     { WM_SETREDRAW, sent|defwinproc|optional },/* in the 2nd MDI child */
243     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },/* in the 2nd MDI child */
244     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },/* in the 2nd MDI child */
245     { WM_WINDOWPOSCHANGED, sent|defwinproc|optional },/* in the 2nd MDI child */
246     { WM_CREATE, hook },
247     /* Restore 2nd MDI child */
248     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED  },/* in the 2nd MDI child */
249     { WM_GETMINMAXINFO, sent|defwinproc|optional },/* in the 2nd MDI child */
250     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },/* in the 2nd MDI child */
251     { WM_WINDOWPOSCHANGED, sent|defwinproc|optional },/* in the 2nd MDI child */
252     { WM_MOVE, sent|defwinproc|optional },/* in the 2nd MDI child */
253     { WM_SIZE, sent|defwinproc|optional },/* in the 2nd MDI child */
254     /* Redraw 2nd MDI child */
255     { WM_SETREDRAW, sent|defwinproc|optional },/* in the 2nd MDI child */
256     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_FRAMECHANGED|SWP_NOMOVE },/* in the 1st MDI child */
257     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },/* in the 1st MDI child */
258     { WM_WINDOWPOSCHANGED, sent|defwinproc|optional},/* in the 1st MDI child */
259     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_FRAMECHANGED|SWP_NOMOVE },/* in the MDI frame */
260     { WM_NCCALCSIZE, sent|wparam, 1 },/* in the MDI frame */
261     { WM_WINDOWPOSCHANGED, sent},/* in the MDI frame */
262     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },/* in the 1st MDI child */
263     { WM_NCACTIVATE, sent|defwinproc|optional },/* in the 1st MDI child */
264     { WM_SETVISIBLE, hook },
265     { WM_KILLFOCUS, sent|defwinproc|optional },/* in the 2nd MDI child */
266     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
267     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
268     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
269     { WM_SETFOCUS, sent },/* in the MDI client */
270     { WM_SETVISIBLE, hook},
271     { WM_KILLFOCUS, sent },/* in the MDI client */
272     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
273     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
274     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
275     { WM_SETFOCUS, sent|defwinproc|optional },/* in the 1st MDI child */
276     { WM_MDIACTIVATE, sent|defwinproc|optional },/* in the 1st MDI child */
277     { WM_WINDOWPOSCHANGED, sent },/* in the 1st MDI child */
278     { 0 }
279 };
280
281 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
282                 SWP_NOZORDER|SWP_FRAMECHANGED)
283  * for a visible overlapped window with WS_CLIPCHILDREN style set.
284  */
285 static const struct message WmSWP_FrameChanged_clip[] = {
286     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
287     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
288     { WM_NCPAINT, sent|parent }, /* wparam != 1 */
289     { WM_GETTEXT, sent|parent|defwinproc|optional },
290     { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
291     { WM_NCPAINT, sent }, /* wparam != 1 */
292     { WM_ERASEBKGND, sent },
293     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
294     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
295     { WM_PAINT, sent },
296     { 0 }
297 };
298 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|
299                 SWP_NOZORDER|SWP_FRAMECHANGED)
300  * for a visible overlapped window.
301  */
302 static const struct message WmSWP_FrameChangedDeferErase[] = {
303     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
304     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
305     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
306     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
307     { WM_PAINT, sent|parent },
308     { WM_NCPAINT, sent|beginpaint|parent }, /* wparam != 1 */
309     { WM_GETTEXT, sent|beginpaint|parent|defwinproc|optional },
310     { WM_PAINT, sent },
311     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
312     { WM_ERASEBKGND, sent|beginpaint },
313     { 0 }
314 };
315
316 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
317                 SWP_NOZORDER|SWP_FRAMECHANGED)
318  * for a visible overlapped window without WS_CLIPCHILDREN style set.
319  */
320 static const struct message WmSWP_FrameChanged_noclip[] = {
321     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
322     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
323     { WM_NCPAINT, sent|parent }, /* wparam != 1 */
324     { WM_GETTEXT, sent|parent|defwinproc|optional },
325     { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
326     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
327     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
328     { WM_PAINT, sent },
329     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
330     { WM_ERASEBKGND, sent|beginpaint },
331     { 0 }
332 };
333
334 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
335 static const struct message WmShowOverlappedSeq[] = {
336     { WM_SHOWWINDOW, sent|wparam, 1 },
337     { WM_NCPAINT, sent|wparam|optional, 1 },
338     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
339     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
340     { WM_NCPAINT, sent|wparam|optional, 1 },
341     { WM_GETTEXT, sent|defwinproc|optional },
342     { WM_ERASEBKGND, sent|optional },
343     { HCBT_ACTIVATE, hook },
344     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
345     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
346     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
347     { WM_NCPAINT, sent|wparam|optional, 1 },
348     { WM_ACTIVATEAPP, sent|wparam, 1 },
349     { WM_NCACTIVATE, sent|wparam, 1 },
350     { WM_GETTEXT, sent|defwinproc|optional },
351     { WM_ACTIVATE, sent|wparam, 1 },
352     { HCBT_SETFOCUS, hook },
353     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
354     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
355     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
356     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
357     { WM_NCPAINT, sent|wparam|optional, 1 },
358     { WM_GETTEXT, sent|defwinproc|optional },
359     { WM_ERASEBKGND, sent|optional },
360     /* Win9x adds SWP_NOZORDER below */
361     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
362     { WM_NCCALCSIZE, sent|optional },
363     { WM_NCPAINT, sent|optional },
364     { WM_ERASEBKGND, sent|optional },
365 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
366        * messages. Does that mean that CreateWindow doesn't set initial
367        * window dimensions for overlapped windows?
368        */
369     { WM_SIZE, sent },
370     { WM_MOVE, sent },
371 #endif
372     { 0 }
373 };
374 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible overlapped window */
375 static const struct message WmShowMaxOverlappedSeq[] = {
376     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
377     { WM_GETMINMAXINFO, sent },
378     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
379     { WM_GETMINMAXINFO, sent|defwinproc },
380     { WM_NCCALCSIZE, sent|wparam, TRUE },
381     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
382     { HCBT_ACTIVATE, hook },
383     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
384     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
385     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
386     { WM_ACTIVATEAPP, sent|wparam, 1 },
387     { WM_NCACTIVATE, sent|wparam, 1 },
388     { WM_GETTEXT, sent|defwinproc|optional },
389     { WM_ACTIVATE, sent|wparam, 1 },
390     { HCBT_SETFOCUS, hook },
391     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
392     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
393     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
394     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
395     { WM_NCPAINT, sent|wparam|optional, 1 },
396     { WM_GETTEXT, sent|defwinproc|optional },
397     { WM_ERASEBKGND, sent|optional },
398     /* Win9x adds SWP_NOZORDER below */
399     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
400     { WM_MOVE, sent|defwinproc },
401     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
402     { WM_NCCALCSIZE, sent|optional },
403     { WM_NCPAINT, sent|optional },
404     { WM_ERASEBKGND, sent|optional },
405     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
406     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
407     { 0 }
408 };
409 /* ShowWindow(SW_SHOWMINIMIZED) for a not visible overlapped window */
410 static const struct message WmShowMinOverlappedSeq[] = {
411     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
412     { HCBT_SETFOCUS, hook },
413     { WM_KILLFOCUS, sent },
414     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
415     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
416     { WM_GETTEXT, sent|optional },
417     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCOPYBITS|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
418     { WM_GETMINMAXINFO, sent|defwinproc },
419     { WM_NCCALCSIZE, sent|wparam, TRUE },
420     { WM_NCPAINT, sent },
421     { WM_GETTEXT, sent|defwinproc|optional },
422     { WM_WINDOWPOSCHANGED, sent },
423     { WM_MOVE, sent|defwinproc },
424     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
425     { WM_NCCALCSIZE, sent|optional },
426     { WM_NCACTIVATE, sent|wparam, 0 },
427     { WM_GETTEXT, sent|defwinproc|optional },
428     { WM_ACTIVATE, sent },
429     { WM_ACTIVATEAPP, sent|wparam, 0 },
430     { 0 }
431 };
432 /* ShowWindow(SW_HIDE) for a visible overlapped window */
433 static const struct message WmHideOverlappedSeq[] = {
434     { WM_SHOWWINDOW, sent|wparam, 0 },
435     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
436     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
437     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
438     { WM_SIZE, sent|optional }, /* XP doesn't send it */
439     { WM_MOVE, sent|optional }, /* XP doesn't send it */
440     { WM_NCACTIVATE, sent|wparam, 0 },
441     { WM_ACTIVATE, sent|wparam, 0 },
442     { WM_ACTIVATEAPP, sent|wparam, 0 },
443     { WM_KILLFOCUS, sent|wparam, 0 },
444     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
445     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
446     { 0 }
447 };
448 /* DestroyWindow for a visible overlapped window */
449 static const struct message WmDestroyOverlappedSeq[] = {
450     { HCBT_DESTROYWND, hook },
451     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
452     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
453     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
454     { WM_NCACTIVATE, sent|wparam, 0 },
455     { WM_ACTIVATE, sent|wparam, 0 },
456     { WM_ACTIVATEAPP, sent|wparam, 0 },
457     { WM_KILLFOCUS, sent|wparam, 0 },
458     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
459     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
460     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
461     { WM_DESTROY, sent },
462     { WM_NCDESTROY, sent },
463     { 0 }
464 };
465 /* CreateWindow(WS_MAXIMIZE|WS_VISIBLE) for popup window */
466 static const struct message WmCreateMaxPopupSeq[] = {
467     { HCBT_CREATEWND, hook },
468     { WM_NCCREATE, sent },
469     { WM_NCCALCSIZE, sent|wparam, 0 },
470     { WM_CREATE, sent },
471     { WM_SIZE, sent|wparam, SIZE_RESTORED },
472     { WM_MOVE, sent },
473     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
474     { WM_GETMINMAXINFO, sent },
475     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|0x8000 },
476     { WM_NCCALCSIZE, sent|wparam, TRUE },
477     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|0x8000 },
478     { WM_MOVE, sent|defwinproc },
479     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
480     { WM_SHOWWINDOW, sent|wparam, 1 },
481     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
482     { HCBT_ACTIVATE, hook },
483     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
484     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
485     { WM_ACTIVATEAPP, sent|wparam, 1 },
486     { WM_NCACTIVATE, sent|wparam, 1 },
487     { WM_ACTIVATE, sent|wparam, 1 },
488     { HCBT_SETFOCUS, hook },
489     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
490     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
491     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
492     { WM_SYNCPAINT, sent|wparam|optional, 4 },
493     { WM_NCPAINT, sent|wparam|optional, 1 },
494     { WM_ERASEBKGND, sent|optional },
495     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
496     { 0 }
497 };
498 /* CreateWindow(WS_MAXIMIZE) for popup window, not initially visible */
499 static const struct message WmCreateInvisibleMaxPopupSeq[] = {
500     { HCBT_CREATEWND, hook },
501     { WM_NCCREATE, sent },
502     { WM_NCCALCSIZE, sent|wparam, 0 },
503     { WM_CREATE, sent },
504     { WM_SIZE, sent|wparam, SIZE_RESTORED },
505     { WM_MOVE, sent },
506     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
507     { WM_GETMINMAXINFO, sent },
508     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|0x8000 },
509     { WM_NCCALCSIZE, sent|wparam, TRUE },
510     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|0x8000 },
511     { WM_MOVE, sent|defwinproc },
512     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
513     { 0 }
514 };
515 /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */
516 static const struct message WmShowMaxPopupResizedSeq[] = {
517     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
518     { WM_GETMINMAXINFO, sent },
519     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
520     { WM_NCCALCSIZE, sent|wparam, TRUE },
521     { HCBT_ACTIVATE, hook },
522     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
523     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
524     { WM_ACTIVATEAPP, sent|wparam, 1 },
525     { WM_NCACTIVATE, sent|wparam, 1 },
526     { WM_ACTIVATE, sent|wparam, 1 },
527     { HCBT_SETFOCUS, hook },
528     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
529     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
530     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
531     { WM_NCPAINT, sent|wparam|optional, 1 },
532     { WM_ERASEBKGND, sent|optional },
533     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE },
534     /* WinNT4.0 sends WM_MOVE */
535     { WM_MOVE, sent|defwinproc|optional },
536     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
537     { 0 }
538 };
539 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible popup window */
540 static const struct message WmShowMaxPopupSeq[] = {
541     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
542     { WM_GETMINMAXINFO, sent },
543     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
544     { WM_NCCALCSIZE, sent|wparam, TRUE },
545     { HCBT_ACTIVATE, hook },
546     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
547     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
548     { WM_ACTIVATEAPP, sent|wparam, 1 },
549     { WM_NCACTIVATE, sent|wparam, 1 },
550     { WM_ACTIVATE, sent|wparam, 1 },
551     { HCBT_SETFOCUS, hook },
552     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
553     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
554     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
555     { WM_SYNCPAINT, sent|wparam|optional, 4 },
556     { WM_NCPAINT, sent|wparam|optional, 1 },
557     { WM_ERASEBKGND, sent|optional },
558     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE },
559     { 0 }
560 };
561 /* CreateWindow(WS_VISIBLE) for popup window */
562 static const struct message WmCreatePopupSeq[] = {
563     { HCBT_CREATEWND, hook },
564     { WM_NCCREATE, sent },
565     { WM_NCCALCSIZE, sent|wparam, 0 },
566     { WM_CREATE, sent },
567     { WM_SIZE, sent|wparam, SIZE_RESTORED },
568     { WM_MOVE, sent },
569     { WM_SHOWWINDOW, sent|wparam, 1 },
570     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
571     { HCBT_ACTIVATE, hook },
572     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
573     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
574     { WM_NCPAINT, sent|wparam|optional, 1 },
575     { WM_ERASEBKGND, sent|optional },
576     { WM_ACTIVATEAPP, sent|wparam, 1 },
577     { WM_NCACTIVATE, sent|wparam, 1 },
578     { WM_ACTIVATE, sent|wparam, 1 },
579     { HCBT_SETFOCUS, hook },
580     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
581     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
582     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
583     { WM_SYNCPAINT, sent|wparam|optional, 4 },
584     { WM_NCPAINT, sent|wparam|optional, 1 },
585     { WM_ERASEBKGND, sent|optional },
586     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
587     { 0 }
588 };
589 /* ShowWindow(SW_SHOWMAXIMIZED) for a visible popup window */
590 static const struct message WmShowVisMaxPopupSeq[] = {
591     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
592     { WM_GETMINMAXINFO, sent },
593     { WM_GETTEXT, sent|optional },
594     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
595     { WM_NCCALCSIZE, sent|wparam, TRUE },
596     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
597     { WM_NCPAINT, sent|wparam|optional, 1 },
598     { WM_ERASEBKGND, sent|optional },
599     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|0x8000 },
600     { WM_MOVE, sent|defwinproc },
601     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
602     { 0 }
603 };
604 /* CreateWindow (for a child popup window, not initially visible) */
605 static const struct message WmCreateChildPopupSeq[] = {
606     { HCBT_CREATEWND, hook },
607     { WM_NCCREATE, sent }, 
608     { WM_NCCALCSIZE, sent|wparam, 0 },
609     { WM_CREATE, sent },
610     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
611     { WM_SIZE, sent|wparam, SIZE_RESTORED },
612     { WM_MOVE, sent },
613     { 0 }
614 };
615 /* CreateWindow (for a popup window, not initially visible,
616  * which sets WS_VISIBLE in WM_CREATE handler)
617  */
618 static const struct message WmCreateInvisiblePopupSeq[] = {
619     { HCBT_CREATEWND, hook },
620     { WM_NCCREATE, sent }, 
621     { WM_NCCALCSIZE, sent|wparam, 0 },
622     { WM_CREATE, sent },
623     { WM_STYLECHANGING, sent },
624     { WM_STYLECHANGED, sent },
625     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
626     { WM_SIZE, sent|wparam, SIZE_RESTORED },
627     { WM_MOVE, sent },
628     { 0 }
629 };
630 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
631  * for a popup window with WS_VISIBLE style set
632  */
633 static const struct message WmShowVisiblePopupSeq_2[] = {
634     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
635     { 0 }
636 };
637 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
638  * for a popup window with WS_VISIBLE style set
639  */
640 static const struct message WmShowVisiblePopupSeq_3[] = {
641     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
642     { HCBT_ACTIVATE, hook },
643     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
644     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
645     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
646     { WM_NCACTIVATE, sent|wparam, 1 },
647     { WM_ACTIVATE, sent|wparam, 1 },
648     { HCBT_SETFOCUS, hook },
649     { WM_KILLFOCUS, sent|parent },
650     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
651     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
652     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
653     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
654     { WM_SETFOCUS, sent|defwinproc },
655     { 0 }
656 };
657 /* CreateWindow (for child window, not initially visible) */
658 static const struct message WmCreateChildSeq[] = {
659     { HCBT_CREATEWND, hook },
660     { WM_NCCREATE, sent }, 
661     /* child is inserted into parent's child list after WM_NCCREATE returns */
662     { WM_NCCALCSIZE, sent|wparam, 0 },
663     { WM_CREATE, sent },
664     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
665     { WM_SIZE, sent|wparam, SIZE_RESTORED },
666     { WM_MOVE, sent },
667     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
668     { 0 }
669 };
670 /* CreateWindow (for maximized child window, not initially visible) */
671 static const struct message WmCreateMaximizedChildSeq[] = {
672     { HCBT_CREATEWND, hook },
673     { WM_NCCREATE, sent }, 
674     { WM_NCCALCSIZE, sent|wparam, 0 },
675     { WM_CREATE, sent },
676     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
677     { WM_SIZE, sent|wparam, SIZE_RESTORED },
678     { WM_MOVE, sent },
679     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
680     { WM_GETMINMAXINFO, sent },
681     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
682     { WM_NCCALCSIZE, sent|wparam, 1 },
683     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|0x8000 },
684     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
685     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
686     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
687     { 0 }
688 };
689 /* CreateWindow (for a child window, initially visible) */
690 static const struct message WmCreateVisibleChildSeq[] = {
691     { HCBT_CREATEWND, hook },
692     { WM_NCCREATE, sent }, 
693     /* child is inserted into parent's child list after WM_NCCREATE returns */
694     { WM_NCCALCSIZE, sent|wparam, 0 },
695     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
696     { WM_CREATE, sent },
697     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
698     { WM_SIZE, sent|wparam, SIZE_RESTORED },
699     { WM_MOVE, sent },
700     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
701     { WM_SHOWWINDOW, sent|wparam, 1 },
702     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
703     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
704     { WM_ERASEBKGND, sent|parent|optional },
705     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
706     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */
707     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
708     { 0 }
709 };
710 /* ShowWindow(SW_SHOW) for a not visible child window */
711 static const struct message WmShowChildSeq[] = {
712     { WM_SHOWWINDOW, sent|wparam, 1 },
713     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
714     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
715     { WM_ERASEBKGND, sent|parent|optional },
716     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
717     { 0 }
718 };
719 /* ShowWindow(SW_HIDE) for a visible child window */
720 static const struct message WmHideChildSeq[] = {
721     { WM_SHOWWINDOW, sent|wparam, 0 },
722     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
723     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
724     { WM_ERASEBKGND, sent|parent|optional },
725     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
726     { 0 }
727 };
728 /* ShowWindow(SW_HIDE) for a visible child window checking all parent events*/
729 static const struct message WmHideChildSeq2[] = {
730     { WM_SHOWWINDOW, sent|wparam, 0 },
731     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
732     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
733     { WM_ERASEBKGND, sent|parent },
734     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
735     { 0 }
736 };
737 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
738  * for a not visible child window
739  */
740 static const struct message WmShowChildSeq_2[] = {
741     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
742     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
743     { WM_CHILDACTIVATE, sent },
744     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
745     { 0 }
746 };
747 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
748  * for a not visible child window
749  */
750 static const struct message WmShowChildSeq_3[] = {
751     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
752     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
753     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
754     { 0 }
755 };
756 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
757  * for a visible child window with a caption
758  */
759 static const struct message WmShowChildSeq_4[] = {
760     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
761     { WM_CHILDACTIVATE, sent },
762     { 0 }
763 };
764 /* ShowWindow(SW_MINIMIZE) for child with invisible parent */
765 static const struct message WmShowChildInvisibleParentSeq_1[] = {
766     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
767     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|0x8000 },
768     { WM_NCCALCSIZE, sent|wparam, 1 },
769     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|0x8000 },
770     { WM_MOVE, sent|defwinproc },
771     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
772     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
773     /* FIXME: Wine creates an icon/title window while Windows doesn't */
774     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
775     { WM_GETTEXT, sent|optional },
776     { 0 }
777 };
778 /* repeated ShowWindow(SW_MINIMIZE) for child with invisible parent */
779 static const struct message WmShowChildInvisibleParentSeq_1r[] = {
780     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
781     { 0 }
782 };
783 /* ShowWindow(SW_MAXIMIZE) for child with invisible parent */
784 static const struct message WmShowChildInvisibleParentSeq_2[] = {
785     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
786     { WM_GETMINMAXINFO, sent },
787     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
788     { WM_NCCALCSIZE, sent|wparam, 1 },
789     { WM_CHILDACTIVATE, sent },
790     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|0x8000 },
791     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
792     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
793     { 0 }
794 };
795 /* repeated ShowWindow(SW_MAXIMIZE) for child with invisible parent */
796 static const struct message WmShowChildInvisibleParentSeq_2r[] = {
797     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
798     { 0 }
799 };
800 /* ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
801 static const struct message WmShowChildInvisibleParentSeq_3[] = {
802     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
803     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
804     { WM_NCCALCSIZE, sent|wparam, 1 },
805     { WM_CHILDACTIVATE, sent },
806     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|0x8000 },
807     { WM_MOVE, sent|defwinproc },
808     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
809     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
810     /* FIXME: Wine creates an icon/title window while Windows doesn't */
811     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
812     { WM_GETTEXT, sent|optional },
813     { 0 }
814 };
815 /* repeated ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
816 static const struct message WmShowChildInvisibleParentSeq_3r[] = {
817     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
818     { 0 }
819 };
820 /* ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
821 static const struct message WmShowChildInvisibleParentSeq_4[] = {
822     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
823     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|0x8000 },
824     { WM_NCCALCSIZE, sent|wparam, 1 },
825     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|0x8000 },
826     { WM_MOVE, sent|defwinproc },
827     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
828     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
829     /* FIXME: Wine creates an icon/title window while Windows doesn't */
830     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
831     { WM_GETTEXT, sent|optional },
832     { 0 }
833 };
834 /* repeated ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
835 static const struct message WmShowChildInvisibleParentSeq_4r[] = {
836     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
837     { 0 }
838 };
839 /* ShowWindow(SW_SHOW) for child with invisible parent */
840 static const struct message WmShowChildInvisibleParentSeq_5[] = {
841     { WM_SHOWWINDOW, sent|wparam, 1 },
842     { 0 }
843 };
844 /* ShowWindow(SW_HIDE) for child with invisible parent */
845 static const struct message WmHideChildInvisibleParentSeq[] = {
846     { WM_SHOWWINDOW, sent|wparam, 0 },
847     { 0 }
848 };
849 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
850 static const struct message WmShowChildInvisibleParentSeq_6[] = {
851     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
852     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
853     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
854     { 0 }
855 };
856 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
857 static const struct message WmHideChildInvisibleParentSeq_2[] = {
858     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
859     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
860     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
861     { 0 }
862 };
863 /* DestroyWindow for a visible child window */
864 static const struct message WmDestroyChildSeq[] = {
865     { HCBT_DESTROYWND, hook },
866     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
867     { WM_SHOWWINDOW, sent|wparam, 0 },
868     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
869     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
870     { WM_ERASEBKGND, sent|parent|optional },
871     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
872     { HCBT_SETFOCUS, hook }, /* set focus to a parent */
873     { WM_KILLFOCUS, sent },
874     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
875     { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
876     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
877     { WM_SETFOCUS, sent|parent },
878     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
879     { WM_DESTROY, sent },
880     { WM_DESTROY, sent|optional }, /* some other (IME?) window */
881     { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
882     { WM_NCDESTROY, sent },
883     { 0 }
884 };
885 /* DestroyWindow for a visible child window with invisible parent */
886 static const struct message WmDestroyInvisibleChildSeq[] = {
887     { HCBT_DESTROYWND, hook },
888     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
889     { WM_SHOWWINDOW, sent|wparam, 0 },
890     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
891     { WM_DESTROY, sent },
892     { WM_NCDESTROY, sent },
893     { 0 }
894 };
895 /* Moving the mouse in nonclient area */
896 static const struct message WmMouseMoveInNonClientAreaSeq[] = { /* FIXME: add */
897     { WM_NCHITTEST, sent },
898     { WM_SETCURSOR, sent },
899     { WM_NCMOUSEMOVE, posted },
900     { 0 }
901 };
902 /* Moving the mouse in client area */
903 static const struct message WmMouseMoveInClientAreaSeq[] = { /* FIXME: add */
904     { WM_NCHITTEST, sent },
905     { WM_SETCURSOR, sent },
906     { WM_MOUSEMOVE, posted },
907     { 0 }
908 };
909 /* Moving by dragging the title bar (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
910 static const struct message WmDragTitleBarSeq[] = { /* FIXME: add */
911     { WM_NCLBUTTONDOWN, sent|wparam, HTCAPTION },
912     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_MOVE+2 },
913     { WM_GETMINMAXINFO, sent|defwinproc },
914     { WM_ENTERSIZEMOVE, sent|defwinproc },
915     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
916     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
917     { WM_MOVE, sent|defwinproc },
918     { WM_EXITSIZEMOVE, sent|defwinproc },
919     { 0 }
920 };
921 /* Sizing by dragging the thick borders (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
922 static const struct message WmDragThickBordersBarSeq[] = { /* FIXME: add */
923     { WM_NCLBUTTONDOWN, sent|wparam, 0xd },
924     { WM_SYSCOMMAND, sent|defwinproc|wparam, 0xf004 },
925     { WM_GETMINMAXINFO, sent|defwinproc },
926     { WM_ENTERSIZEMOVE, sent|defwinproc },
927     { WM_SIZING, sent|defwinproc|wparam, 4}, /* one for each mouse movement */
928     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
929     { WM_GETMINMAXINFO, sent|defwinproc },
930     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
931     { WM_NCPAINT, sent|defwinproc|wparam, 1 },
932     { WM_GETTEXT, sent|defwinproc },
933     { WM_ERASEBKGND, sent|defwinproc },
934     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
935     { WM_MOVE, sent|defwinproc },
936     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
937     { WM_EXITSIZEMOVE, sent|defwinproc },
938     { 0 }
939 };
940 /* Resizing child window with MoveWindow (32) */
941 static const struct message WmResizingChildWithMoveWindowSeq[] = {
942     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
943     { WM_NCCALCSIZE, sent|wparam, 1 },
944     { WM_ERASEBKGND, sent|optional },
945     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE },
946     { WM_MOVE, sent|defwinproc },
947     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
948     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
949     { 0 }
950 };
951 /* Clicking on inactive button */
952 static const struct message WmClickInactiveButtonSeq[] = { /* FIXME: add */
953     { WM_NCHITTEST, sent },
954     { WM_PARENTNOTIFY, sent|parent|wparam, WM_LBUTTONDOWN },
955     { WM_MOUSEACTIVATE, sent },
956     { WM_MOUSEACTIVATE, sent|parent|defwinproc },
957     { WM_SETCURSOR, sent },
958     { WM_SETCURSOR, sent|parent|defwinproc },
959     { WM_LBUTTONDOWN, posted },
960     { WM_KILLFOCUS, posted|parent },
961     { WM_SETFOCUS, posted },
962     { WM_CTLCOLORBTN, posted|parent },
963     { BM_SETSTATE, posted },
964     { WM_CTLCOLORBTN, posted|parent },
965     { WM_LBUTTONUP, posted },
966     { BM_SETSTATE, posted },
967     { WM_CTLCOLORBTN, posted|parent },
968     { WM_COMMAND, posted|parent },
969     { 0 }
970 };
971 /* Reparenting a button (16/32) */
972 /* The last child (button) reparented gets topmost for its new parent. */
973 static const struct message WmReparentButtonSeq[] = { /* FIXME: add */
974     { WM_SHOWWINDOW, sent|wparam, 0 },
975     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
976     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
977     { WM_ERASEBKGND, sent|parent },
978     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
979     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
980     { WM_CHILDACTIVATE, sent },
981     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW },
982     { WM_MOVE, sent|defwinproc },
983     { WM_SHOWWINDOW, sent|wparam, 1 },
984     { 0 }
985 };
986 /* Creation of a custom dialog (32) */
987 static const struct message WmCreateCustomDialogSeq[] = {
988     { HCBT_CREATEWND, hook },
989     { WM_GETMINMAXINFO, sent },
990     { WM_NCCREATE, sent },
991     { WM_NCCALCSIZE, sent|wparam, 0 },
992     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
993     { WM_CREATE, sent },
994     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
995     { WM_SHOWWINDOW, sent|wparam, 1 },
996     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
997     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
998     { HCBT_ACTIVATE, hook },
999     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1000
1001
1002     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1003
1004     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1005
1006     { WM_NCACTIVATE, sent|wparam, 1 },
1007     { WM_GETTEXT, sent|optional|defwinproc },
1008     { WM_GETTEXT, sent|optional|defwinproc },
1009     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
1010     { WM_ACTIVATE, sent|wparam, 1 },
1011     { WM_KILLFOCUS, sent|parent },
1012     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1013     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1014     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1015     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1016     { WM_SETFOCUS, sent },
1017     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1018     { WM_NCPAINT, sent|wparam, 1 },
1019     { WM_GETTEXT, sent|optional|defwinproc },
1020     { WM_GETTEXT, sent|optional|defwinproc },
1021     { WM_ERASEBKGND, sent },
1022     { WM_CTLCOLORDLG, sent|defwinproc },
1023     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1024     { WM_GETTEXT, sent|optional },
1025     { WM_GETTEXT, sent|optional },
1026     { WM_NCCALCSIZE, sent|optional },
1027     { WM_NCPAINT, sent|optional },
1028     { WM_GETTEXT, sent|optional|defwinproc },
1029     { WM_GETTEXT, sent|optional|defwinproc },
1030     { WM_ERASEBKGND, sent|optional },
1031     { WM_CTLCOLORDLG, sent|optional|defwinproc },
1032     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1033     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1034     { WM_MOVE, sent },
1035     { 0 }
1036 };
1037 /* Calling EndDialog for a custom dialog (32) */
1038 static const struct message WmEndCustomDialogSeq[] = {
1039     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1040     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1041     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1042     { WM_GETTEXT, sent|optional },
1043     { HCBT_ACTIVATE, hook },
1044     { WM_NCACTIVATE, sent|wparam, 0 },
1045     { WM_GETTEXT, sent|optional|defwinproc },
1046     { WM_GETTEXT, sent|optional|defwinproc },
1047     { WM_ACTIVATE, sent|wparam, 0 },
1048     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1049     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1050     { HCBT_SETFOCUS, hook },
1051     { WM_KILLFOCUS, sent },
1052     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1053     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1054     { WM_IME_NOTIFY, sent|wparam|optional, 1 },
1055     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1056     { WM_SETFOCUS, sent|parent|defwinproc },
1057     { 0 }
1058 };
1059 /* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
1060 static const struct message WmShowCustomDialogSeq[] = {
1061     { WM_SHOWWINDOW, sent|wparam, 1 },
1062     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1063     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1064     { HCBT_ACTIVATE, hook },
1065     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1066
1067     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1068
1069     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1070     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
1071     { WM_NCACTIVATE, sent|wparam, 1 },
1072     { WM_ACTIVATE, sent|wparam, 1 },
1073
1074     { WM_KILLFOCUS, sent|parent },
1075     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1076     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1077     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1078     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1079     { WM_SETFOCUS, sent },
1080     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1081     { WM_NCPAINT, sent|wparam, 1 },
1082     { WM_ERASEBKGND, sent },
1083     { WM_CTLCOLORDLG, sent|defwinproc },
1084     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1085     { 0 }
1086 };
1087 /* Creation and destruction of a modal dialog (32) */
1088 static const struct message WmModalDialogSeq[] = {
1089     { WM_CANCELMODE, sent|parent },
1090     { HCBT_SETFOCUS, hook },
1091     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1092     { WM_KILLFOCUS, sent|parent },
1093     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1094     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1095     { WM_ENABLE, sent|parent|wparam, 0 },
1096     { HCBT_CREATEWND, hook },
1097     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1098     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1099     { WM_SETFONT, sent },
1100     { WM_INITDIALOG, sent },
1101     { WM_CHANGEUISTATE, sent|optional },
1102     { WM_UPDATEUISTATE, sent|optional },
1103     { WM_SHOWWINDOW, sent },
1104     { HCBT_ACTIVATE, hook },
1105     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1106     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1107     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1108     { WM_NCACTIVATE, sent|wparam, 1 },
1109     { WM_GETTEXT, sent|optional },
1110     { WM_ACTIVATE, sent|wparam, 1 },
1111     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1112     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1113     { WM_NCPAINT, sent },
1114     { WM_GETTEXT, sent|optional },
1115     { WM_ERASEBKGND, sent },
1116     { WM_CTLCOLORDLG, sent },
1117     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1118     { WM_GETTEXT, sent|optional },
1119     { WM_NCCALCSIZE, sent|optional },
1120     { WM_NCPAINT, sent|optional },
1121     { WM_GETTEXT, sent|optional },
1122     { WM_ERASEBKGND, sent|optional },
1123     { WM_CTLCOLORDLG, sent|optional },
1124     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1125     { WM_PAINT, sent|optional },
1126     { WM_CTLCOLORBTN, sent },
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_ENTERIDLE, sent|parent|optional },
1141     { WM_ENTERIDLE, sent|parent|optional },
1142     { WM_ENTERIDLE, sent|parent|optional },
1143     { WM_ENTERIDLE, sent|parent|optional },
1144     { WM_ENTERIDLE, sent|parent|optional },
1145     { WM_ENTERIDLE, sent|parent|optional },
1146     { WM_ENTERIDLE, sent|parent|optional },
1147     { WM_TIMER, sent },
1148     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1149     { WM_ENABLE, sent|parent|wparam, 1 },
1150     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1151     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1152     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1153     { WM_GETTEXT, sent|optional },
1154     { HCBT_ACTIVATE, hook },
1155     { WM_NCACTIVATE, sent|wparam, 0 },
1156     { WM_GETTEXT, sent|optional },
1157     { WM_ACTIVATE, sent|wparam, 0 },
1158     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1159     { WM_WINDOWPOSCHANGING, sent|optional },
1160     { HCBT_SETFOCUS, hook },
1161     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1162     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1163     { WM_SETFOCUS, sent|parent|defwinproc },
1164     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 },
1165     { HCBT_DESTROYWND, hook },
1166     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1167     { WM_DESTROY, sent },
1168     { WM_NCDESTROY, sent },
1169     { 0 }
1170 };
1171 /* Creation of a modal dialog that is resized inside WM_INITDIALOG (32) */
1172 static const struct message WmCreateModalDialogResizeSeq[] = { /* FIXME: add */
1173     /* (inside dialog proc, handling WM_INITDIALOG) */
1174     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1175     { WM_NCCALCSIZE, sent },
1176     { WM_NCACTIVATE, sent|parent|wparam, 0 },
1177     { WM_GETTEXT, sent|defwinproc },
1178     { WM_ACTIVATE, sent|parent|wparam, 0 },
1179     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1180     { WM_WINDOWPOSCHANGING, sent|parent },
1181     { WM_NCACTIVATE, sent|wparam, 1 },
1182     { WM_ACTIVATE, sent|wparam, 1 },
1183     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1184     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1185     /* (setting focus) */
1186     { WM_SHOWWINDOW, sent|wparam, 1 },
1187     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1188     { WM_NCPAINT, sent },
1189     { WM_GETTEXT, sent|defwinproc },
1190     { WM_ERASEBKGND, sent },
1191     { WM_CTLCOLORDLG, sent|defwinproc },
1192     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1193     { WM_PAINT, sent },
1194     /* (bunch of WM_CTLCOLOR* for each control) */
1195     { WM_PAINT, sent|parent },
1196     { WM_ENTERIDLE, sent|parent|wparam, 0 },
1197     { WM_SETCURSOR, sent|parent },
1198     { 0 }
1199 };
1200 /* SetMenu for NonVisible windows with size change*/
1201 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
1202     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1203     { WM_NCCALCSIZE, sent|wparam, 1 },
1204     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1205     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
1206     { WM_MOVE, sent|defwinproc },
1207     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1208     { WM_NCCALCSIZE,sent|wparam|optional, 1 }, /* XP */
1209     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1210     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1211     { WM_GETTEXT, sent|optional },
1212     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1213     { 0 }
1214 };
1215 /* SetMenu for NonVisible windows with no size change */
1216 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
1217     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1218     { WM_NCCALCSIZE, sent|wparam, 1 },
1219     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1220     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1221     { 0 }
1222 };
1223 /* SetMenu for Visible windows with size change */
1224 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
1225     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1226     { WM_NCCALCSIZE, sent|wparam, 1 },
1227     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1228     { WM_NCPAINT, sent }, /* wparam != 1 */
1229     { WM_GETTEXT, sent|defwinproc|optional },
1230     { WM_ERASEBKGND, sent|optional },
1231     { WM_ACTIVATE, sent|optional },
1232     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1233     { WM_MOVE, sent|defwinproc },
1234     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1235     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1236     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1237     { WM_ERASEBKGND, sent|optional },
1238     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1239     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1240     { 0 }
1241 };
1242 /* SetMenu for Visible windows with no size change */
1243 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
1244     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1245     { WM_NCCALCSIZE, sent|wparam, 1 },
1246     { WM_NCPAINT, sent }, /* wparam != 1 */
1247     { WM_GETTEXT, sent|defwinproc|optional },
1248     { WM_ERASEBKGND, sent|optional },
1249     { WM_ACTIVATE, sent|optional },
1250     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1251     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1252     { 0 }
1253 };
1254 /* DrawMenuBar for a visible window */
1255 static const struct message WmDrawMenuBarSeq[] =
1256 {
1257     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1258     { WM_NCCALCSIZE, sent|wparam, 1 },
1259     { WM_NCPAINT, sent }, /* wparam != 1 */
1260     { WM_GETTEXT, sent|defwinproc|optional },
1261     { WM_ERASEBKGND, sent|optional },
1262     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1263     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1264     { 0 }
1265 };
1266
1267 static const struct message WmSetRedrawFalseSeq[] =
1268 {
1269     { WM_SETREDRAW, sent|wparam, 0 },
1270     { 0 }
1271 };
1272
1273 static const struct message WmSetRedrawTrueSeq[] =
1274 {
1275     { WM_SETREDRAW, sent|wparam, 1 },
1276     { 0 }
1277 };
1278
1279 static const struct message WmEnableWindowSeq_1[] =
1280 {
1281     { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1282     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1283     { WM_ENABLE, sent|wparam|lparam, FALSE, 0 },
1284     { 0 }
1285 };
1286
1287 static const struct message WmEnableWindowSeq_2[] =
1288 {
1289     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1290     { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
1291     { 0 }
1292 };
1293
1294 static const struct message WmGetScrollRangeSeq[] =
1295 {
1296     { SBM_GETRANGE, sent },
1297     { 0 }
1298 };
1299 static const struct message WmGetScrollInfoSeq[] =
1300 {
1301     { SBM_GETSCROLLINFO, sent },
1302     { 0 }
1303 };
1304 static const struct message WmSetScrollRangeSeq[] =
1305 {
1306     /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
1307        sends SBM_SETSCROLLINFO.
1308      */
1309     { SBM_SETSCROLLINFO, sent },
1310     { 0 }
1311 };
1312 /* SetScrollRange for a window without a non-client area */
1313 static const struct message WmSetScrollRangeHSeq_empty[] =
1314 {
1315     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_HSCROLL, 0 },
1316     { 0 }
1317 };
1318 static const struct message WmSetScrollRangeVSeq_empty[] =
1319 {
1320     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_VSCROLL, 0 },
1321     { 0 }
1322 };
1323 static const struct message WmSetScrollRangeHVSeq[] =
1324 {
1325     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1326     { WM_NCCALCSIZE, sent|wparam, 1 },
1327     { WM_GETTEXT, sent|defwinproc|optional },
1328     { WM_ERASEBKGND, sent|optional },
1329     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1330     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1331     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1332     { 0 }
1333 };
1334 /* SetScrollRange for a window with a non-client area */
1335 static const struct message WmSetScrollRangeHV_NC_Seq[] =
1336 {
1337     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1338     { WM_NCCALCSIZE, sent|wparam, 1 },
1339     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1340     { WM_NCPAINT, sent|optional },
1341     { WM_GETTEXT, sent|defwinproc|optional },
1342     { WM_GETTEXT, sent|defwinproc|optional },
1343     { WM_ERASEBKGND, sent|optional },
1344     { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
1345     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE },
1346     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1347     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1348     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1349     { WM_GETTEXT, sent|optional },
1350     { WM_GETTEXT, sent|optional },
1351     { WM_GETTEXT, sent|optional },
1352     { WM_GETTEXT, sent|optional },
1353     { 0 }
1354 };
1355 /* test if we receive the right sequence of messages */
1356 /* after calling ShowWindow( SW_SHOWNA) */
1357 static const struct message WmSHOWNAChildInvisParInvis[] = {
1358     { WM_SHOWWINDOW, sent|wparam, 1 },
1359     { 0 }
1360 };
1361 static const struct message WmSHOWNAChildVisParInvis[] = {
1362     { WM_SHOWWINDOW, sent|wparam, 1 },
1363     { 0 }
1364 };
1365 static const struct message WmSHOWNAChildVisParVis[] = {
1366     { WM_SHOWWINDOW, sent|wparam, 1 },
1367     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1368     { 0 }
1369 };
1370 static const struct message WmSHOWNAChildInvisParVis[] = {
1371     { WM_SHOWWINDOW, sent|wparam, 1 },
1372     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1373     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1374     { WM_ERASEBKGND, sent|optional },
1375     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOCLIENTMOVE },
1376     { 0 }
1377 };
1378 static const struct message WmSHOWNATopVisible[] = {
1379     { WM_SHOWWINDOW, sent|wparam, 1 },
1380     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1381     { 0 }
1382 };
1383 static const struct message WmSHOWNATopInvisible[] = {
1384     { WM_SHOWWINDOW, sent|wparam, 1 },
1385     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1386     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1387     { WM_NCPAINT, sent|wparam, 1 },
1388     { WM_GETTEXT, sent|defwinproc|optional },
1389     { WM_ERASEBKGND, sent|optional },
1390     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1391     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1392     { WM_NCPAINT, sent|wparam|optional, 1 },
1393     { WM_ERASEBKGND, sent|optional },
1394     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1395     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1396     { WM_MOVE, sent },
1397     { 0 }
1398 };
1399
1400 static int after_end_dialog, test_def_id;
1401 static int sequence_cnt, sequence_size;
1402 static struct message* sequence;
1403 static int log_all_parent_messages;
1404
1405 /* user32 functions */
1406 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
1407 static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG);
1408 static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD);
1409 static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*);
1410 static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
1411 /* kernel32 functions */
1412 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
1413
1414 static void init_procs(void)
1415 {
1416     HMODULE user32 = GetModuleHandleA("user32.dll");
1417     HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
1418
1419 #define GET_PROC(dll, func) \
1420     p ## func = (void*)GetProcAddress(dll, #func); \
1421     if(!p ## func) { \
1422       trace("GetProcAddress(%s) failed\n", #func); \
1423     }
1424
1425     GET_PROC(user32, GetAncestor)
1426     GET_PROC(user32, NotifyWinEvent)
1427     GET_PROC(user32, SetWinEventHook)
1428     GET_PROC(user32, TrackMouseEvent)
1429     GET_PROC(user32, UnhookWinEvent)
1430
1431     GET_PROC(kernel32, GetCPInfoExA)
1432
1433 #undef GET_PROC
1434 }
1435
1436 static void add_message(const struct message *msg)
1437 {
1438     if (!sequence) 
1439     {
1440         sequence_size = 10;
1441         sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof (struct message) );
1442     }
1443     if (sequence_cnt == sequence_size) 
1444     {
1445         sequence_size *= 2;
1446         sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof (struct message) );
1447     }
1448     assert(sequence);
1449
1450     sequence[sequence_cnt].message = msg->message;
1451     sequence[sequence_cnt].flags = msg->flags;
1452     sequence[sequence_cnt].wParam = msg->wParam;
1453     sequence[sequence_cnt].lParam = msg->lParam;
1454
1455     sequence_cnt++;
1456 }
1457
1458 /* try to make sure pending X events have been processed before continuing */
1459 static void flush_events(void)
1460 {
1461     MSG msg;
1462     int diff = 100;
1463     DWORD time = GetTickCount() + diff;
1464
1465     while (diff > 0)
1466     {
1467         if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min(10,diff), QS_ALLINPUT ) == WAIT_TIMEOUT) break;
1468         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
1469         diff = time - GetTickCount();
1470     }
1471 }
1472
1473 static void flush_sequence(void)
1474 {
1475     HeapFree(GetProcessHeap(), 0, sequence);
1476     sequence = 0;
1477     sequence_cnt = sequence_size = 0;
1478 }
1479
1480 #define ok_sequence( exp, contx, todo) \
1481         ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
1482
1483
1484 static void ok_sequence_(const struct message *expected, const char *context, int todo,
1485         const char *file, int line)
1486 {
1487     static const struct message end_of_sequence = { 0, 0, 0, 0 };
1488     const struct message *actual;
1489     int failcount = 0;
1490     
1491     add_message(&end_of_sequence);
1492
1493     actual = sequence;
1494
1495     while (expected->message && actual->message)
1496     {
1497         trace_( file, line)("expected %04x - actual %04x\n", expected->message, actual->message);
1498
1499         if (expected->message == actual->message)
1500         {
1501             if (expected->flags & wparam)
1502             {
1503                 if (expected->wParam != actual->wParam && todo)
1504                 {
1505                     todo_wine {
1506                         failcount ++;
1507                         ok_( file, line) (FALSE,
1508                             "%s: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
1509                             context, expected->message, expected->wParam, actual->wParam);
1510                     }
1511                 }
1512                 else
1513                 ok_( file, line) (expected->wParam == actual->wParam,
1514                      "%s: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
1515                      context, expected->message, expected->wParam, actual->wParam);
1516             }
1517             if (expected->flags & lparam)
1518             {
1519                 if (expected->lParam != actual->lParam && todo)
1520                 {
1521                     todo_wine {
1522                         failcount ++;
1523                         ok_( file, line) (FALSE,
1524                             "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
1525                             context, expected->message, expected->lParam, actual->lParam);
1526                     }
1527                 }
1528                 else
1529                  ok_( file, line) (expected->lParam == actual->lParam,
1530                      "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
1531                      context, expected->message, expected->lParam, actual->lParam);
1532             }
1533             if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
1534             {
1535                     todo_wine {
1536                         failcount ++;
1537                         ok_( file, line) (FALSE,
1538                             "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
1539                             context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
1540                     }
1541             }
1542             else
1543                 ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
1544                     "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
1545                     context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
1546             ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
1547                 "%s: the msg 0x%04x should %shave been sent by BeginPaint\n",
1548                 context, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
1549             ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
1550                 "%s: the msg 0x%04x should have been %s\n",
1551                 context, expected->message, (expected->flags & posted) ? "posted" : "sent");
1552             ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
1553                 "%s: the msg 0x%04x was expected in %s\n",
1554                 context, expected->message, (expected->flags & parent) ? "parent" : "child");
1555             ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
1556                 "%s: the msg 0x%04x should have been sent by a hook\n",
1557                 context, expected->message);
1558             ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
1559                 "%s: the msg 0x%04x should have been sent by a winevent hook\n",
1560                 context, expected->message);
1561             expected++;
1562             actual++;
1563         }
1564         /* silently drop winevent messages if there is no support for them */
1565         else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
1566             expected++;
1567         else if (todo)
1568         {
1569             failcount++;
1570             todo_wine {
1571                 ok_( file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
1572                     context, expected->message, actual->message);
1573             }
1574             flush_sequence();
1575             return;
1576         }
1577         else
1578         {
1579             ok_( file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
1580                 context, expected->message, actual->message);
1581             expected++;
1582             actual++;
1583         }
1584     }
1585
1586     /* skip all optional trailing messages */
1587     while (expected->message && ((expected->flags & optional) ||
1588             ((expected->flags & winevent_hook) && !hEvent_hook)))
1589         expected++;
1590
1591     if (todo)
1592     {
1593         todo_wine {
1594             if (expected->message || actual->message) {
1595                 failcount++;
1596                 ok_( file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
1597                     context, expected->message, actual->message);
1598             }
1599         }
1600     }
1601     else
1602     {
1603         if (expected->message || actual->message)
1604             ok_( file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
1605                 context, expected->message, actual->message);
1606     }
1607     if( todo && !failcount) /* succeeded yet marked todo */
1608         todo_wine {
1609             ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
1610         }
1611
1612     flush_sequence();
1613 }
1614
1615 /******************************** MDI test **********************************/
1616
1617 /* CreateWindow for MDI frame window, initially visible */
1618 static const struct message WmCreateMDIframeSeq[] = {
1619     { HCBT_CREATEWND, hook },
1620     { WM_GETMINMAXINFO, sent },
1621     { WM_NCCREATE, sent },
1622     { WM_NCCALCSIZE, sent|wparam, 0 },
1623     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1624     { WM_CREATE, sent },
1625     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1626     { WM_SHOWWINDOW, sent|wparam, 1 },
1627     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1628     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1629     { HCBT_ACTIVATE, hook },
1630     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1631     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1632     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
1633     { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
1634     { WM_NCACTIVATE, sent|wparam, 1 },
1635     { WM_GETTEXT, sent|defwinproc|optional },
1636     { WM_ACTIVATE, sent|wparam, 1 },
1637     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
1638     { HCBT_SETFOCUS, hook },
1639     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1640     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1641     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1642     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
1643     /* Win9x adds SWP_NOZORDER below */
1644     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1645     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
1646     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1647     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1648     { WM_MOVE, sent },
1649     { 0 }
1650 };
1651 /* DestroyWindow for MDI frame window, initially visible */
1652 static const struct message WmDestroyMDIframeSeq[] = {
1653     { HCBT_DESTROYWND, hook },
1654     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1655     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1656     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
1657     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1658     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
1659     { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
1660     { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
1661     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
1662     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1663     { WM_DESTROY, sent },
1664     { WM_NCDESTROY, sent },
1665     { 0 }
1666 };
1667 /* CreateWindow for MDI client window, initially visible */
1668 static const struct message WmCreateMDIclientSeq[] = {
1669     { HCBT_CREATEWND, hook },
1670     { WM_NCCREATE, sent },
1671     { WM_NCCALCSIZE, sent|wparam, 0 },
1672     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
1673     { WM_CREATE, sent },
1674     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
1675     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1676     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1677     { WM_MOVE, sent },
1678     { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
1679     { WM_SHOWWINDOW, sent|wparam, 1 },
1680     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1681     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1682     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1683     { 0 }
1684 };
1685 /* ShowWindow(SW_SHOW) for MDI client window */
1686 static const struct message WmShowMDIclientSeq[] = {
1687     { WM_SHOWWINDOW, sent|wparam, 1 },
1688     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1689     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1690     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1691     { 0 }
1692 };
1693 /* ShowWindow(SW_HIDE) for MDI client window */
1694 static const struct message WmHideMDIclientSeq[] = {
1695     { WM_SHOWWINDOW, sent|wparam, 0 },
1696     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1697     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
1698     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
1699     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1700     { 0 }
1701 };
1702 /* DestroyWindow for MDI client window, initially visible */
1703 static const struct message WmDestroyMDIclientSeq[] = {
1704     { HCBT_DESTROYWND, hook },
1705     { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
1706     { WM_SHOWWINDOW, sent|wparam, 0 },
1707     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1708     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1709     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1710     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1711     { WM_DESTROY, sent },
1712     { WM_NCDESTROY, sent },
1713     { 0 }
1714 };
1715 /* CreateWindow for MDI child window, initially visible */
1716 static const struct message WmCreateMDIchildVisibleSeq[] = {
1717     { HCBT_CREATEWND, hook },
1718     { WM_NCCREATE, sent }, 
1719     { WM_NCCALCSIZE, sent|wparam, 0 },
1720     { WM_CREATE, sent },
1721     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1722     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1723     { WM_MOVE, sent },
1724     /* Win2k sends wparam set to
1725      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1726      * while Win9x doesn't bother to set child window id according to
1727      * CLIENTCREATESTRUCT.idFirstChild
1728      */
1729     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1730     { WM_SHOWWINDOW, sent|wparam, 1 },
1731     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1732     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1733     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1734     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1735     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1736     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1737     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1738
1739     /* Win9x: message sequence terminates here. */
1740
1741     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1742     { HCBT_SETFOCUS, hook }, /* in MDI client */
1743     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1744     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
1745     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1746     { WM_SETFOCUS, sent }, /* in MDI client */
1747     { HCBT_SETFOCUS, hook },
1748     { WM_KILLFOCUS, sent }, /* in MDI client */
1749     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1750     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1751     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1752     { WM_SETFOCUS, sent|defwinproc },
1753     { WM_MDIACTIVATE, sent|defwinproc },
1754     { 0 }
1755 };
1756 /* CreateWindow for MDI child window with invisible parent */
1757 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
1758     { HCBT_CREATEWND, hook },
1759     { WM_GETMINMAXINFO, sent },
1760     { WM_NCCREATE, sent }, 
1761     { WM_NCCALCSIZE, sent|wparam, 0 },
1762     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
1763     { WM_CREATE, sent },
1764     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1765     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1766     { WM_MOVE, sent },
1767     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1768     { WM_SHOWWINDOW, sent|wparam, 1 },
1769     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
1770     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1771     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1772     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1773
1774     /* Win9x: message sequence terminates here. */
1775
1776     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1777     { HCBT_SETFOCUS, hook }, /* in MDI client */
1778     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1779     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
1780     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1781     { WM_SETFOCUS, sent }, /* in MDI client */
1782     { HCBT_SETFOCUS, hook },
1783     { WM_KILLFOCUS, sent }, /* in MDI client */
1784     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1785     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1786     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1787     { WM_SETFOCUS, sent|defwinproc },
1788     { WM_MDIACTIVATE, sent|defwinproc },
1789     { 0 }
1790 };
1791 /* DestroyWindow for MDI child window, initially visible */
1792 static const struct message WmDestroyMDIchildVisibleSeq[] = {
1793     { HCBT_DESTROYWND, hook },
1794     /* Win2k sends wparam set to
1795      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1796      * while Win9x doesn't bother to set child window id according to
1797      * CLIENTCREATESTRUCT.idFirstChild
1798      */
1799     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1800     { WM_SHOWWINDOW, sent|wparam, 0 },
1801     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1802     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1803     { WM_ERASEBKGND, sent|parent|optional },
1804     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1805
1806     /* { WM_DESTROY, sent }
1807      * Win9x: message sequence terminates here.
1808      */
1809
1810     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1811     { WM_KILLFOCUS, sent },
1812     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1813     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1814     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1815     { WM_SETFOCUS, sent }, /* in MDI client */
1816
1817     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1818     { WM_KILLFOCUS, sent }, /* in MDI client */
1819     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1820     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1821     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1822     { WM_SETFOCUS, sent }, /* in MDI client */
1823
1824     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1825
1826     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1827     { WM_KILLFOCUS, sent },
1828     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1829     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1830     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1831     { WM_SETFOCUS, sent }, /* in MDI client */
1832
1833     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1834     { WM_KILLFOCUS, sent }, /* in MDI client */
1835     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1836     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1837     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1838     { WM_SETFOCUS, sent }, /* in MDI client */
1839
1840     { WM_DESTROY, sent },
1841
1842     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1843     { WM_KILLFOCUS, sent },
1844     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1845     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1846     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1847     { WM_SETFOCUS, sent }, /* in MDI client */
1848
1849     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1850     { WM_KILLFOCUS, sent }, /* in MDI client */
1851     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1852     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1853     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1854     { WM_SETFOCUS, sent }, /* in MDI client */
1855
1856     { WM_NCDESTROY, sent },
1857     { 0 }
1858 };
1859 /* CreateWindow for MDI child window, initially invisible */
1860 static const struct message WmCreateMDIchildInvisibleSeq[] = {
1861     { HCBT_CREATEWND, hook },
1862     { WM_NCCREATE, sent }, 
1863     { WM_NCCALCSIZE, sent|wparam, 0 },
1864     { WM_CREATE, sent },
1865     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1866     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1867     { WM_MOVE, sent },
1868     /* Win2k sends wparam set to
1869      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1870      * while Win9x doesn't bother to set child window id according to
1871      * CLIENTCREATESTRUCT.idFirstChild
1872      */
1873     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1874     { 0 }
1875 };
1876 /* DestroyWindow for MDI child window, initially invisible */
1877 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
1878     { HCBT_DESTROYWND, hook },
1879     /* Win2k sends wparam set to
1880      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1881      * while Win9x doesn't bother to set child window id according to
1882      * CLIENTCREATESTRUCT.idFirstChild
1883      */
1884     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1885     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1886     { WM_DESTROY, sent },
1887     { WM_NCDESTROY, sent },
1888     /* FIXME: Wine destroys an icon/title window while Windows doesn't */
1889     { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */
1890     { 0 }
1891 };
1892 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
1893 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
1894     { HCBT_CREATEWND, hook },
1895     { WM_NCCREATE, sent }, 
1896     { WM_NCCALCSIZE, sent|wparam, 0 },
1897     { WM_CREATE, sent },
1898     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1899     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1900     { WM_MOVE, sent },
1901     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1902     { WM_GETMINMAXINFO, sent },
1903     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
1904     { WM_NCCALCSIZE, sent|wparam, 1 },
1905     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1906     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1907      /* in MDI frame */
1908     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1909     { WM_NCCALCSIZE, sent|wparam, 1 },
1910     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1911     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1912     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
1913     /* Win2k sends wparam set to
1914      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1915      * while Win9x doesn't bother to set child window id according to
1916      * CLIENTCREATESTRUCT.idFirstChild
1917      */
1918     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1919     { WM_SHOWWINDOW, sent|wparam, 1 },
1920     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1921     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1922     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1923     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1924     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1925     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1926     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1927
1928     /* Win9x: message sequence terminates here. */
1929
1930     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1931     { HCBT_SETFOCUS, hook }, /* in MDI client */
1932     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1933     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
1934     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1935     { WM_SETFOCUS, sent }, /* in MDI client */
1936     { HCBT_SETFOCUS, hook },
1937     { WM_KILLFOCUS, sent }, /* in MDI client */
1938     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1939     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1940     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1941     { WM_SETFOCUS, sent|defwinproc },
1942     { WM_MDIACTIVATE, sent|defwinproc },
1943      /* in MDI frame */
1944     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1945     { WM_NCCALCSIZE, sent|wparam, 1 },
1946     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1947     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1948     { 0 }
1949 };
1950 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
1951 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
1952     /* restore the 1st MDI child */
1953     { WM_SETREDRAW, sent|wparam, 0 },
1954     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
1955     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
1956     { WM_NCCALCSIZE, sent|wparam, 1 },
1957     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1958     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1959     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1960      /* in MDI frame */
1961     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1962     { WM_NCCALCSIZE, sent|wparam, 1 },
1963     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1964     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1965     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
1966     { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
1967     /* create the 2nd MDI child */
1968     { HCBT_CREATEWND, hook },
1969     { WM_NCCREATE, sent }, 
1970     { WM_NCCALCSIZE, sent|wparam, 0 },
1971     { WM_CREATE, sent },
1972     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1973     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1974     { WM_MOVE, sent },
1975     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1976     { WM_GETMINMAXINFO, sent },
1977     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
1978     { WM_NCCALCSIZE, sent|wparam, 1 },
1979     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1980     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1981     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1982      /* in MDI frame */
1983     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1984     { WM_NCCALCSIZE, sent|wparam, 1 },
1985     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1986     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1987     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
1988     /* Win2k sends wparam set to
1989      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1990      * while Win9x doesn't bother to set child window id according to
1991      * CLIENTCREATESTRUCT.idFirstChild
1992      */
1993     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1994     { WM_SHOWWINDOW, sent|wparam, 1 },
1995     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1996     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1997     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1998     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1999     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2000     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2001
2002     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2003     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2004
2005     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2006
2007     /* Win9x: message sequence terminates here. */
2008
2009     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2010     { HCBT_SETFOCUS, hook },
2011     { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
2012     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
2013     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2014     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2015     { WM_SETFOCUS, sent }, /* in MDI client */
2016     { HCBT_SETFOCUS, hook },
2017     { WM_KILLFOCUS, sent }, /* in MDI client */
2018     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2019     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2020     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2021     { WM_SETFOCUS, sent|defwinproc },
2022
2023     { WM_MDIACTIVATE, sent|defwinproc },
2024      /* in MDI frame */
2025     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2026     { WM_NCCALCSIZE, sent|wparam, 1 },
2027     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2028     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2029     { 0 }
2030 };
2031 /* WM_MDICREATE MDI child window, initially visible and maximized */
2032 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
2033     { WM_MDICREATE, sent },
2034     { HCBT_CREATEWND, hook },
2035     { WM_NCCREATE, sent }, 
2036     { WM_NCCALCSIZE, sent|wparam, 0 },
2037     { WM_CREATE, sent },
2038     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2039     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2040     { WM_MOVE, sent },
2041     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2042     { WM_GETMINMAXINFO, sent },
2043     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
2044     { WM_NCCALCSIZE, sent|wparam, 1 },
2045     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2046     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2047
2048      /* in MDI frame */
2049     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2050     { WM_NCCALCSIZE, sent|wparam, 1 },
2051     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2052     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2053     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2054
2055     /* Win2k sends wparam set to
2056      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2057      * while Win9x doesn't bother to set child window id according to
2058      * CLIENTCREATESTRUCT.idFirstChild
2059      */
2060     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2061     { WM_SHOWWINDOW, sent|wparam, 1 },
2062     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2063
2064     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2065
2066     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2067     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2068     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2069
2070     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2071     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2072
2073     /* Win9x: message sequence terminates here. */
2074
2075     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2076     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2077     { HCBT_SETFOCUS, hook }, /* in MDI client */
2078     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2079     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
2080     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2081     { HCBT_SETFOCUS, hook|optional },
2082     { WM_KILLFOCUS, sent }, /* in MDI client */
2083     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2084     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2085     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2086     { WM_SETFOCUS, sent|defwinproc },
2087
2088     { WM_MDIACTIVATE, sent|defwinproc },
2089
2090      /* in MDI child */
2091     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2092     { WM_NCCALCSIZE, sent|wparam, 1 },
2093     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2094     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2095
2096      /* in MDI frame */
2097     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2098     { WM_NCCALCSIZE, sent|wparam, 1 },
2099     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2100     { WM_MOVE, sent|defwinproc },
2101     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2102
2103      /* in MDI client */
2104     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2105     { WM_NCCALCSIZE, sent|wparam, 1 },
2106     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2107     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2108
2109      /* in MDI child */
2110     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2111     { WM_NCCALCSIZE, sent|wparam, 1 },
2112     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2113     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2114
2115     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2116     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2117     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
2118     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2119     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2120
2121     { 0 }
2122 };
2123 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
2124 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
2125     { HCBT_CREATEWND, hook },
2126     { WM_GETMINMAXINFO, sent },
2127     { WM_NCCREATE, sent }, 
2128     { WM_NCCALCSIZE, sent|wparam, 0 },
2129     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2130     { WM_CREATE, sent },
2131     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2132     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2133     { WM_MOVE, sent },
2134     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2135     { WM_GETMINMAXINFO, sent },
2136     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
2137     { WM_GETMINMAXINFO, sent|defwinproc },
2138     { WM_NCCALCSIZE, sent|wparam, 1 },
2139     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|0x8000 },
2140     { WM_MOVE, sent|defwinproc },
2141     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2142      /* in MDI frame */
2143     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2144     { WM_NCCALCSIZE, sent|wparam, 1 },
2145     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2146     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2147     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
2148     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2149     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2150     /* Win2k sends wparam set to
2151      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2152      * while Win9x doesn't bother to set child window id according to
2153      * CLIENTCREATESTRUCT.idFirstChild
2154      */
2155     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2156     { 0 }
2157 };
2158 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
2159 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
2160     { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
2161     { HCBT_SYSCOMMAND, hook },
2162     { WM_CLOSE, sent|defwinproc },
2163     { WM_MDIDESTROY, sent }, /* in MDI client */
2164
2165     /* bring the 1st MDI child to top */
2166     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
2167     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
2168
2169     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2170
2171     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
2172     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2173     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2174
2175     /* maximize the 1st MDI child */
2176     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2177     { WM_GETMINMAXINFO, sent|defwinproc },
2178     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|0x8000 },
2179     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2180     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
2181     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2182     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2183
2184     /* restore the 2nd MDI child */
2185     { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
2186     { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
2187     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|0x8000 },
2188     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2189
2190     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2191
2192     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2193     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2194
2195     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2196
2197     { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
2198      /* in MDI frame */
2199     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2200     { WM_NCCALCSIZE, sent|wparam, 1 },
2201     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2202     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2203     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2204
2205     /* bring the 1st MDI child to top */
2206     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2207     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2208     { HCBT_SETFOCUS, hook },
2209     { WM_KILLFOCUS, sent|defwinproc },
2210     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
2211     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2212     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2213     { WM_SETFOCUS, sent }, /* in MDI client */
2214     { HCBT_SETFOCUS, hook },
2215     { WM_KILLFOCUS, sent }, /* in MDI client */
2216     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2217     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2218     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2219     { WM_SETFOCUS, sent|defwinproc },
2220     { WM_MDIACTIVATE, sent|defwinproc },
2221     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2222
2223     /* apparently ShowWindow(SW_SHOW) on an MDI client */
2224     { WM_SHOWWINDOW, sent|wparam, 1 },
2225     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2226     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2227     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2228     { WM_MDIREFRESHMENU, sent },
2229
2230     { HCBT_DESTROYWND, hook },
2231     /* Win2k sends wparam set to
2232      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2233      * while Win9x doesn't bother to set child window id according to
2234      * CLIENTCREATESTRUCT.idFirstChild
2235      */
2236     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2237     { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
2238     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2239     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2240     { WM_ERASEBKGND, sent|parent|optional },
2241     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2242
2243     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2244     { WM_DESTROY, sent|defwinproc },
2245     { WM_NCDESTROY, sent|defwinproc },
2246     { 0 }
2247 };
2248 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
2249 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
2250     { WM_MDIDESTROY, sent }, /* in MDI client */
2251     { WM_SHOWWINDOW, sent|wparam, 0 },
2252     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2253     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2254     { WM_ERASEBKGND, sent|parent|optional },
2255     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2256
2257     { HCBT_SETFOCUS, hook },
2258     { WM_KILLFOCUS, sent },
2259     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2260     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2261     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2262     { WM_SETFOCUS, sent }, /* in MDI client */
2263     { HCBT_SETFOCUS, hook },
2264     { WM_KILLFOCUS, sent }, /* in MDI client */
2265     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2266     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2267     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2268     { WM_SETFOCUS, sent },
2269
2270      /* in MDI child */
2271     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2272     { WM_NCCALCSIZE, sent|wparam, 1 },
2273     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2274     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2275
2276      /* in MDI frame */
2277     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2278     { WM_NCCALCSIZE, sent|wparam, 1 },
2279     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2280     { WM_MOVE, sent|defwinproc },
2281     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2282
2283      /* in MDI client */
2284     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2285     { WM_NCCALCSIZE, sent|wparam, 1 },
2286     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2287     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2288
2289      /* in MDI child */
2290     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2291     { WM_NCCALCSIZE, sent|wparam, 1 },
2292     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2293     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2294
2295      /* in MDI child */
2296     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2297     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2298     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2299     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2300
2301      /* in MDI frame */
2302     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2303     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2304     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2305     { WM_MOVE, sent|defwinproc },
2306     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2307
2308      /* in MDI client */
2309     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2310     { WM_NCCALCSIZE, sent|wparam, 1 },
2311     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2312     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2313
2314      /* in MDI child */
2315     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
2316     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2317     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2318     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2319     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2320     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2321
2322     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
2323
2324     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2325     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2326     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2327     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2328     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2329
2330      /* in MDI frame */
2331     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2332     { WM_NCCALCSIZE, sent|wparam, 1 },
2333     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2334     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2335
2336     { WM_NCACTIVATE, sent|wparam, 0 },
2337     { WM_MDIACTIVATE, sent },
2338
2339     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2340     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|0x8000 },
2341     { WM_NCCALCSIZE, sent|wparam, 1 },
2342
2343     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2344
2345     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2346     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|0x8000 },
2347     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2348
2349      /* in MDI child */
2350     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2351     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2352     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2353     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2354
2355      /* in MDI frame */
2356     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2357     { WM_NCCALCSIZE, sent|wparam, 1 },
2358     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2359     { WM_MOVE, sent|defwinproc },
2360     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2361
2362      /* in MDI client */
2363     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2364     { WM_NCCALCSIZE, sent|wparam, 1 },
2365     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2366     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2367     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2368     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2369     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2370     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2371     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2372
2373     { HCBT_SETFOCUS, hook },
2374     { WM_KILLFOCUS, sent },
2375     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2376     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2377     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2378     { WM_SETFOCUS, sent }, /* in MDI client */
2379
2380     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2381
2382     { HCBT_DESTROYWND, hook },
2383     /* Win2k sends wparam set to
2384      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2385      * while Win9x doesn't bother to set child window id according to
2386      * CLIENTCREATESTRUCT.idFirstChild
2387      */
2388     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2389
2390     { WM_SHOWWINDOW, sent|wparam, 0 },
2391     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2392     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2393     { WM_ERASEBKGND, sent|parent|optional },
2394     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2395
2396     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2397     { WM_DESTROY, sent },
2398     { WM_NCDESTROY, sent },
2399     { 0 }
2400 };
2401 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
2402 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
2403     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2404     { WM_GETMINMAXINFO, sent },
2405     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
2406     { WM_NCCALCSIZE, sent|wparam, 1 },
2407     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2408     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2409
2410     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2411     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2412     { HCBT_SETFOCUS, hook },
2413     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2414     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2415     { WM_SETFOCUS, sent }, /* in MDI client */
2416     { HCBT_SETFOCUS, hook },
2417     { WM_KILLFOCUS, sent }, /* in MDI client */
2418     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2419     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2420     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2421     { WM_SETFOCUS, sent|defwinproc },
2422     { WM_MDIACTIVATE, sent|defwinproc },
2423     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2424     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2425      /* in MDI frame */
2426     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2427     { WM_NCCALCSIZE, sent|wparam, 1 },
2428     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2429     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2430     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2431     { 0 }
2432 };
2433 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
2434 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
2435     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2436     { WM_GETMINMAXINFO, sent },
2437     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
2438     { WM_GETMINMAXINFO, sent|defwinproc },
2439     { WM_NCCALCSIZE, sent|wparam, 1 },
2440     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2441     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2442
2443     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2444     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2445     { HCBT_SETFOCUS, hook },
2446     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2447     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2448     { WM_SETFOCUS, sent }, /* in MDI client */
2449     { HCBT_SETFOCUS, hook },
2450     { WM_KILLFOCUS, sent }, /* in MDI client */
2451     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2452     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2453     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2454     { WM_SETFOCUS, sent|defwinproc },
2455     { WM_MDIACTIVATE, sent|defwinproc },
2456     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2457     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2458     { 0 }
2459 };
2460 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
2461 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
2462     { WM_MDIMAXIMIZE, sent }, /* in MDI client */
2463     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2464     { WM_GETMINMAXINFO, sent },
2465     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
2466     { WM_GETMINMAXINFO, sent|defwinproc },
2467     { WM_NCCALCSIZE, sent|wparam, 1 },
2468     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
2469     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2470     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|0x8000 },
2471     { WM_MOVE, sent|defwinproc },
2472     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2473
2474     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2475     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2476     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2477     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
2478     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2479     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
2480      /* in MDI frame */
2481     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2482     { WM_NCCALCSIZE, sent|wparam, 1 },
2483     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2484     { WM_MOVE, sent|defwinproc },
2485     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2486     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
2487      /* in MDI client */
2488     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2489     { WM_NCCALCSIZE, sent|wparam, 1 },
2490     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2491     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2492      /* in MDI child */
2493     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
2494     { WM_GETMINMAXINFO, sent|defwinproc },
2495     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2496     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2497     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2498     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
2499     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
2500     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2501     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2502     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
2503      /* in MDI frame */
2504     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
2505     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
2506     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
2507     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2508     { 0 }
2509 };
2510 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
2511 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
2512     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2513     { WM_GETMINMAXINFO, sent },
2514     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
2515     { WM_NCCALCSIZE, sent|wparam, 1 },
2516     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2517     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2518     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2519      /* in MDI frame */
2520     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2521     { WM_NCCALCSIZE, sent|wparam, 1 },
2522     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2523     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2524     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2525     { 0 }
2526 };
2527 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
2528 static const struct message WmRestoreMDIchildVisibleSeq[] = {
2529     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
2530     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
2531     { WM_NCCALCSIZE, sent|wparam, 1 },
2532     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2533     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2534     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2535      /* in MDI frame */
2536     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2537     { WM_NCCALCSIZE, sent|wparam, 1 },
2538     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2539     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2540     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2541     { 0 }
2542 };
2543 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
2544 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
2545     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
2546     { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
2547     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
2548     { WM_NCCALCSIZE, sent|wparam, 1 },
2549     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2550     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_NOCLIENTSIZE|0x8000 },
2551     { WM_MOVE, sent|defwinproc },
2552     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2553     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2554     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2555     { HCBT_SETFOCUS, hook },
2556     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2557     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2558     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2559     { WM_SETFOCUS, sent },
2560     { 0 }
2561 };
2562 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
2563 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
2564     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
2565     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|0x8000 },
2566     { WM_NCCALCSIZE, sent|wparam, 1 },
2567     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOCLIENTSIZE|0x8000 },
2568     { WM_MOVE, sent|defwinproc },
2569     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
2570     { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
2571     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2572     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2573     /* FIXME: Wine creates an icon/title window while Windows doesn't */
2574     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */
2575     { 0 }
2576 };
2577 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
2578 static const struct message WmRestoreMDIchildInisibleSeq[] = {
2579     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
2580     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
2581     { WM_NCCALCSIZE, sent|wparam, 1 },
2582     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2583     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2584     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2585     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2586      /* in MDI frame */
2587     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2588     { WM_NCCALCSIZE, sent|wparam, 1 },
2589     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2590     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2591     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2592     { 0 }
2593 };
2594
2595 static HWND mdi_client;
2596 static WNDPROC old_mdi_client_proc;
2597
2598 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2599 {
2600     struct message msg;
2601
2602     /* do not log painting messages */
2603     if (message != WM_PAINT &&
2604         message != WM_NCPAINT &&
2605         message != WM_SYNCPAINT &&
2606         message != WM_ERASEBKGND &&
2607         message != WM_NCPAINT &&
2608         message != WM_NCHITTEST &&
2609         message != WM_GETTEXT &&
2610         message != WM_MDIGETACTIVE &&
2611         message != WM_GETICON &&
2612         message != WM_DEVICECHANGE)
2613     {
2614         trace("mdi client: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
2615
2616         switch (message)
2617         {
2618             case WM_WINDOWPOSCHANGING:
2619             case WM_WINDOWPOSCHANGED:
2620             {
2621                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
2622
2623                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
2624                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
2625                       winpos->hwnd, winpos->hwndInsertAfter,
2626                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
2627                 dump_winpos_flags(winpos->flags);
2628
2629                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2630                  * in the high word for internal purposes
2631                  */
2632                 wParam = winpos->flags & 0xffff;
2633                 /* We are not interested in the flags that don't match under XP and Win9x */
2634                 wParam &= ~(SWP_NOZORDER);
2635                 break;
2636             }
2637         }
2638
2639         msg.message = message;
2640         msg.flags = sent|wparam|lparam;
2641         msg.wParam = wParam;
2642         msg.lParam = lParam;
2643         add_message(&msg);
2644     }
2645
2646     return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
2647 }
2648
2649 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2650 {
2651     static long defwndproc_counter = 0;
2652     LRESULT ret;
2653     struct message msg;
2654
2655     /* do not log painting messages */
2656     if (message != WM_PAINT &&
2657         message != WM_NCPAINT &&
2658         message != WM_SYNCPAINT &&
2659         message != WM_ERASEBKGND &&
2660         message != WM_NCPAINT &&
2661         message != WM_NCHITTEST &&
2662         message != WM_GETTEXT &&
2663         message != WM_GETICON &&
2664         message != WM_DEVICECHANGE)
2665     {
2666         trace("mdi child: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
2667
2668         switch (message)
2669         {
2670             case WM_WINDOWPOSCHANGING:
2671             case WM_WINDOWPOSCHANGED:
2672             {
2673                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
2674
2675                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
2676                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
2677                       winpos->hwnd, winpos->hwndInsertAfter,
2678                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
2679                 dump_winpos_flags(winpos->flags);
2680
2681                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2682                  * in the high word for internal purposes
2683                  */
2684                 wParam = winpos->flags & 0xffff;
2685                 /* We are not interested in the flags that don't match under XP and Win9x */
2686                 wParam &= ~(SWP_NOZORDER);
2687                 break;
2688             }
2689
2690             case WM_MDIACTIVATE:
2691             {
2692                 HWND active, client = GetParent(hwnd);
2693
2694                 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
2695
2696                 if (hwnd == (HWND)lParam) /* if we are being activated */
2697                     ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
2698                 else
2699                     ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
2700                 break;
2701             }
2702         }
2703
2704         msg.message = message;
2705         msg.flags = sent|wparam|lparam;
2706         if (defwndproc_counter) msg.flags |= defwinproc;
2707         msg.wParam = wParam;
2708         msg.lParam = lParam;
2709         add_message(&msg);
2710     }
2711
2712     defwndproc_counter++;
2713     ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
2714     defwndproc_counter--;
2715
2716     return ret;
2717 }
2718
2719 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2720 {
2721     static long defwndproc_counter = 0;
2722     LRESULT ret;
2723     struct message msg;
2724
2725     /* do not log painting messages */
2726     if (message != WM_PAINT &&
2727         message != WM_NCPAINT &&
2728         message != WM_SYNCPAINT &&
2729         message != WM_ERASEBKGND &&
2730         message != WM_NCPAINT &&
2731         message != WM_NCHITTEST &&
2732         message != WM_GETTEXT &&
2733         message != WM_GETICON &&
2734         message != WM_DEVICECHANGE)
2735     {
2736         trace("mdi frame: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
2737
2738         switch (message)
2739         {
2740             case WM_WINDOWPOSCHANGING:
2741             case WM_WINDOWPOSCHANGED:
2742             {
2743                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
2744
2745                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
2746                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
2747                       winpos->hwnd, winpos->hwndInsertAfter,
2748                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
2749                 dump_winpos_flags(winpos->flags);
2750
2751                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2752                  * in the high word for internal purposes
2753                  */
2754                 wParam = winpos->flags & 0xffff;
2755                 /* We are not interested in the flags that don't match under XP and Win9x */
2756                 wParam &= ~(SWP_NOZORDER);
2757                 break;
2758             }
2759         }
2760
2761         msg.message = message;
2762         msg.flags = sent|wparam|lparam;
2763         if (defwndproc_counter) msg.flags |= defwinproc;
2764         msg.wParam = wParam;
2765         msg.lParam = lParam;
2766         add_message(&msg);
2767     }
2768
2769     defwndproc_counter++;
2770     ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
2771     defwndproc_counter--;
2772
2773     return ret;
2774 }
2775
2776 static BOOL mdi_RegisterWindowClasses(void)
2777 {
2778     WNDCLASSA cls;
2779
2780     cls.style = 0;
2781     cls.lpfnWndProc = mdi_frame_wnd_proc;
2782     cls.cbClsExtra = 0;
2783     cls.cbWndExtra = 0;
2784     cls.hInstance = GetModuleHandleA(0);
2785     cls.hIcon = 0;
2786     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
2787     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
2788     cls.lpszMenuName = NULL;
2789     cls.lpszClassName = "MDI_frame_class";
2790     if (!RegisterClassA(&cls)) return FALSE;
2791
2792     cls.lpfnWndProc = mdi_child_wnd_proc;
2793     cls.lpszClassName = "MDI_child_class";
2794     if (!RegisterClassA(&cls)) return FALSE;
2795
2796     if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
2797     old_mdi_client_proc = cls.lpfnWndProc;
2798     cls.hInstance = GetModuleHandleA(0);
2799     cls.lpfnWndProc = mdi_client_hook_proc;
2800     cls.lpszClassName = "MDI_client_class";
2801     if (!RegisterClassA(&cls)) assert(0);
2802
2803     return TRUE;
2804 }
2805
2806 static void test_mdi_messages(void)
2807 {
2808     MDICREATESTRUCTA mdi_cs;
2809     CLIENTCREATESTRUCT client_cs;
2810     HWND mdi_frame, mdi_child, mdi_child2, active_child;
2811     BOOL zoomed;
2812     HMENU hMenu = CreateMenu();
2813
2814     assert(mdi_RegisterWindowClasses());
2815
2816     flush_sequence();
2817
2818     trace("creating MDI frame window\n");
2819     mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
2820                                 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
2821                                 WS_MAXIMIZEBOX | WS_VISIBLE,
2822                                 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
2823                                 GetDesktopWindow(), hMenu,
2824                                 GetModuleHandleA(0), NULL);
2825     assert(mdi_frame);
2826     ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
2827
2828     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2829     ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
2830
2831     trace("creating MDI client window\n");
2832     client_cs.hWindowMenu = 0;
2833     client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
2834     mdi_client = CreateWindowExA(0, "MDI_client_class",
2835                                  NULL,
2836                                  WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
2837                                  0, 0, 0, 0,
2838                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
2839     assert(mdi_client);
2840     ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
2841
2842     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2843     ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
2844
2845     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2846     ok(!active_child, "wrong active MDI child %p\n", active_child);
2847     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2848
2849     SetFocus(0);
2850     flush_sequence();
2851
2852     trace("creating invisible MDI child window\n");
2853     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
2854                                 WS_CHILD,
2855                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
2856                                 mdi_client, 0, GetModuleHandleA(0), NULL);
2857     assert(mdi_child);
2858
2859     flush_sequence();
2860     ShowWindow(mdi_child, SW_SHOWNORMAL);
2861     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
2862
2863     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
2864     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
2865
2866     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2867     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2868
2869     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2870     ok(!active_child, "wrong active MDI child %p\n", active_child);
2871     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2872
2873     ShowWindow(mdi_child, SW_HIDE);
2874     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
2875     flush_sequence();
2876
2877     ShowWindow(mdi_child, SW_SHOW);
2878     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
2879
2880     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
2881     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
2882
2883     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2884     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2885
2886     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2887     ok(!active_child, "wrong active MDI child %p\n", active_child);
2888     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2889
2890     DestroyWindow(mdi_child);
2891     flush_sequence();
2892
2893     trace("creating visible MDI child window\n");
2894     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
2895                                 WS_CHILD | WS_VISIBLE,
2896                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
2897                                 mdi_client, 0, GetModuleHandleA(0), NULL);
2898     assert(mdi_child);
2899     ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
2900
2901     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
2902     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
2903
2904     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2905     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
2906
2907     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2908     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
2909     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2910     flush_sequence();
2911
2912     DestroyWindow(mdi_child);
2913     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
2914
2915     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2916     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2917
2918     /* Win2k: MDI client still returns a just destroyed child as active
2919      * Win9x: MDI client returns 0
2920      */
2921     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2922     ok(active_child == mdi_child || /* win2k */
2923        !active_child, /* win9x */
2924        "wrong active MDI child %p\n", active_child);
2925     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2926
2927     flush_sequence();
2928
2929     trace("creating invisible MDI child window\n");
2930     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
2931                                 WS_CHILD,
2932                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
2933                                 mdi_client, 0, GetModuleHandleA(0), NULL);
2934     assert(mdi_child2);
2935     ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
2936
2937     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
2938     ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
2939
2940     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2941     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2942
2943     /* Win2k: MDI client still returns a just destroyed child as active
2944      * Win9x: MDI client returns mdi_child2
2945      */
2946     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2947     ok(active_child == mdi_child || /* win2k */
2948        active_child == mdi_child2, /* win9x */
2949        "wrong active MDI child %p\n", active_child);
2950     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2951     flush_sequence();
2952
2953     ShowWindow(mdi_child2, SW_MAXIMIZE);
2954     ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
2955
2956     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
2957     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
2958
2959     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2960     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
2961     ok(zoomed, "wrong zoomed state %d\n", zoomed);
2962     flush_sequence();
2963
2964     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2965     ok(GetFocus() == mdi_child2 || /* win2k */
2966        GetFocus() == 0, /* win9x */
2967        "wrong focus window %p\n", GetFocus());
2968
2969     SetFocus(0);
2970     flush_sequence();
2971
2972     ShowWindow(mdi_child2, SW_HIDE);
2973     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
2974
2975     ShowWindow(mdi_child2, SW_RESTORE);
2976     ok_sequence(WmRestoreMDIchildInisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
2977     flush_sequence();
2978
2979     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
2980     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
2981
2982     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2983     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
2984     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2985     flush_sequence();
2986
2987     SetFocus(0);
2988     flush_sequence();
2989
2990     ShowWindow(mdi_child2, SW_HIDE);
2991     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
2992
2993     ShowWindow(mdi_child2, SW_SHOW);
2994     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
2995
2996     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2997     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2998
2999     ShowWindow(mdi_child2, SW_MAXIMIZE);
3000     ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
3001
3002     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3003     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3004
3005     ShowWindow(mdi_child2, SW_RESTORE);
3006     ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
3007
3008     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3009     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3010
3011     ShowWindow(mdi_child2, SW_MINIMIZE);
3012     ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", TRUE);
3013
3014     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3015     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3016
3017     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3018     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3019     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3020     flush_sequence();
3021
3022     ShowWindow(mdi_child2, SW_RESTORE);
3023     ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", TRUE);
3024
3025     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3026     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3027
3028     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3029     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3030     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3031     flush_sequence();
3032
3033     SetFocus(0);
3034     flush_sequence();
3035
3036     ShowWindow(mdi_child2, SW_HIDE);
3037     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3038
3039     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3040     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3041
3042     DestroyWindow(mdi_child2);
3043     ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
3044
3045     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3046     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3047
3048     /* test for maximized MDI children */
3049     trace("creating maximized visible MDI child window 1\n");
3050     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3051                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3052                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3053                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3054     assert(mdi_child);
3055     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
3056     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3057
3058     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3059     ok(GetFocus() == mdi_child || /* win2k */
3060        GetFocus() == 0, /* win9x */
3061        "wrong focus window %p\n", GetFocus());
3062
3063     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3064     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3065     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3066     flush_sequence();
3067
3068     trace("creating maximized visible MDI child window 2\n");
3069     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3070                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3071                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3072                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3073     assert(mdi_child2);
3074     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3075     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3076     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3077
3078     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3079     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3080
3081     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3082     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3083     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3084     flush_sequence();
3085
3086     trace("destroying maximized visible MDI child window 2\n");
3087     DestroyWindow(mdi_child2);
3088     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3089
3090     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3091
3092     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3093     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3094
3095     /* Win2k: MDI client still returns a just destroyed child as active
3096      * Win9x: MDI client returns 0
3097      */
3098     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3099     ok(active_child == mdi_child2 || /* win2k */
3100        !active_child, /* win9x */
3101        "wrong active MDI child %p\n", active_child);
3102     flush_sequence();
3103
3104     ShowWindow(mdi_child, SW_MAXIMIZE);
3105     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3106     flush_sequence();
3107
3108     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3109     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3110
3111     trace("re-creating maximized visible MDI child window 2\n");
3112     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3113                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3114                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3115                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3116     assert(mdi_child2);
3117     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3118     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3119     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3120
3121     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3122     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3123
3124     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3125     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3126     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3127     flush_sequence();
3128
3129     SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
3130     ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
3131     ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
3132
3133     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3134     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3135     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3136
3137     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3138     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3139     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3140     flush_sequence();
3141
3142     DestroyWindow(mdi_child);
3143     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3144
3145     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3146     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
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("creating maximized invisible MDI child window\n");
3158     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3159                                 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
3160                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3161                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3162     assert(mdi_child2);
3163     ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", TRUE);
3164     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3165     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
3166     ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
3167
3168     /* Win2k: MDI client still returns a just destroyed child as active
3169      * Win9x: MDI client returns 0
3170      */
3171     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3172     ok(active_child == mdi_child || /* win2k */
3173        !active_child, /* win9x */
3174        "wrong active MDI child %p\n", active_child);
3175     flush_sequence();
3176
3177     trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
3178     ShowWindow(mdi_child2, SW_MAXIMIZE);
3179     ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
3180     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3181     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3182     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3183
3184     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3185     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3186     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3187     flush_sequence();
3188
3189     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3190     flush_sequence();
3191
3192     /* end of test for maximized MDI children */
3193
3194     mdi_cs.szClass = "MDI_child_Class";
3195     mdi_cs.szTitle = "MDI child";
3196     mdi_cs.hOwner = GetModuleHandleA(0);
3197     mdi_cs.x = 0;
3198     mdi_cs.y = 0;
3199     mdi_cs.cx = CW_USEDEFAULT;
3200     mdi_cs.cy = CW_USEDEFAULT;
3201     mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
3202     mdi_cs.lParam = 0;
3203     mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
3204     ok(mdi_child != 0, "MDI child creation failed\n");
3205     ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
3206
3207     ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
3208
3209     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3210     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3211
3212     ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
3213     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3214     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3215
3216     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3217     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3218     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3219     flush_sequence();
3220
3221     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3222     ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
3223
3224     ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
3225     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3226     ok(!active_child, "wrong active MDI child %p\n", active_child);
3227
3228     SetFocus(0);
3229     flush_sequence();
3230
3231     DestroyWindow(mdi_client);
3232     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3233
3234     /* test maximization of MDI child with invisible parent */
3235     client_cs.hWindowMenu = 0;
3236     mdi_client = CreateWindow("MDI_client_class",
3237                                  NULL,
3238                                  WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
3239                                  0, 0, 660, 430,
3240                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3241     ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
3242
3243     ShowWindow(mdi_client, SW_HIDE);
3244     ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
3245
3246     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3247                                 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
3248                                 0, 0, 650, 440,
3249                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3250     ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
3251
3252     SendMessage(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
3253     ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
3254     zoomed = IsZoomed(mdi_child);
3255     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3256     
3257     ShowWindow(mdi_client, SW_SHOW);
3258     ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
3259
3260     DestroyWindow(mdi_child);
3261     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
3262
3263     /* end of test for maximization of MDI child with invisible parent */
3264
3265     /* test for switch maximized MDI children */
3266     trace("creating maximized visible MDI child window 1(Switch test)\n");
3267     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3268                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3269                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3270                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3271     assert(mdi_child);
3272     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE);
3273     ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n");
3274
3275     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3276     ok(GetFocus() == mdi_child || /* win2k */
3277        GetFocus() == 0, /* win9x */
3278        "wrong focus window %p(Switch test)\n", GetFocus());
3279
3280     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3281     ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3282     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3283     flush_sequence();
3284
3285     trace("creating maximized visible MDI child window 2(Switch test)\n");
3286     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3287                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3288                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3289                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3290     assert(mdi_child2);
3291     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window(Switch test)\n", TRUE);
3292     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n");
3293     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized(Switch test)\n");
3294
3295     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3296     ok(GetFocus() == mdi_child2, "wrong focus window %p(Switch test)\n", GetFocus());
3297
3298     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3299     ok(active_child == mdi_child2, "wrong active MDI child %p(Switch test)\n", active_child);
3300     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3301     flush_sequence();
3302
3303     trace("Switch child window.\n");
3304     SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0);
3305     ok_sequence(WmSwitchChild,"Child not switch correctly\n",TRUE);
3306     
3307     trace("end of test for switch maximized MDI children\n");
3308
3309     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3310     flush_sequence();
3311
3312     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3313     flush_sequence();
3314
3315     /* end of test for switch maximized MDI children */
3316
3317     DestroyWindow(mdi_client);
3318     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3319
3320     DestroyWindow(mdi_frame);
3321     ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
3322 }
3323 /************************* End of MDI test **********************************/
3324
3325 static void test_WM_SETREDRAW(HWND hwnd)
3326 {
3327     DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
3328
3329     flush_sequence();
3330
3331     SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3332     ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
3333
3334     ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
3335     ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
3336
3337     flush_sequence();
3338     SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3339     ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
3340
3341     ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
3342     ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
3343
3344     /* restore original WS_VISIBLE state */
3345     SetWindowLongA(hwnd, GWL_STYLE, style);
3346
3347     flush_sequence();
3348 }
3349
3350 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3351 {
3352     struct message msg;
3353
3354     trace("dialog: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
3355
3356     /* explicitly ignore WM_GETICON message */
3357     if (message == WM_GETICON) return 0;
3358
3359     switch (message)
3360     {
3361         /* ignore */
3362         case WM_MOUSEMOVE:
3363         case WM_SETCURSOR:
3364         case WM_DEVICECHANGE:
3365             return 0;
3366         case WM_NCHITTEST:
3367             return HTCLIENT;
3368
3369         case WM_WINDOWPOSCHANGING:
3370         case WM_WINDOWPOSCHANGED:
3371         {
3372             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
3373
3374             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
3375             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
3376                   winpos->hwnd, winpos->hwndInsertAfter,
3377                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
3378             dump_winpos_flags(winpos->flags);
3379
3380             /* Log only documented flags, win2k uses 0x1000 and 0x2000
3381              * in the high word for internal purposes
3382              */
3383             wParam = winpos->flags & 0xffff;
3384             /* We are not interested in the flags that don't match under XP and Win9x */
3385             wParam &= ~(SWP_NOZORDER);
3386             break;
3387         }
3388     }
3389
3390     msg.message = message;
3391     msg.flags = sent|wparam|lparam;
3392     msg.wParam = wParam;
3393     msg.lParam = lParam;
3394     add_message(&msg);
3395
3396     if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
3397     if (message == WM_TIMER) EndDialog( hwnd, 0 );
3398     return 0;
3399 }
3400
3401 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
3402 {
3403     DWORD style, exstyle;
3404     INT xmin, xmax;
3405     BOOL ret;
3406
3407     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
3408     style = GetWindowLongA(hwnd, GWL_STYLE);
3409     /* do not be confused by WS_DLGFRAME set */
3410     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
3411
3412     if (clear) ok(style & clear, "style %08x should be set\n", clear);
3413     if (set) ok(!(style & set), "style %08x should not be set\n", set);
3414
3415     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3416     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
3417     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
3418         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
3419     else
3420         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
3421
3422     style = GetWindowLongA(hwnd, GWL_STYLE);
3423     if (set) ok(style & set, "style %08x should be set\n", set);
3424     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
3425
3426     /* a subsequent call should do nothing */
3427     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3428     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
3429     ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3430
3431     xmin = 0xdeadbeef;
3432     xmax = 0xdeadbeef;
3433     trace("Ignore GetScrollRange error below if you are on Win9x\n");
3434     ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
3435     ok( ret, "GetScrollRange(%d) error %d\n", ctl, GetLastError());
3436     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3437     ok(xmin == min, "unexpected min scroll value %d\n", xmin);
3438     ok(xmax == max, "unexpected max scroll value %d\n", xmax);
3439 }
3440
3441 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
3442 {
3443     DWORD style, exstyle;
3444     SCROLLINFO si;
3445     BOOL ret;
3446
3447     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
3448     style = GetWindowLongA(hwnd, GWL_STYLE);
3449     /* do not be confused by WS_DLGFRAME set */
3450     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
3451
3452     if (clear) ok(style & clear, "style %08x should be set\n", clear);
3453     if (set) ok(!(style & set), "style %08x should not be set\n", set);
3454
3455     si.cbSize = sizeof(si);
3456     si.fMask = SIF_RANGE;
3457     si.nMin = min;
3458     si.nMax = max;
3459     SetScrollInfo(hwnd, ctl, &si, TRUE);
3460     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
3461         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
3462     else
3463         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
3464
3465     style = GetWindowLongA(hwnd, GWL_STYLE);
3466     if (set) ok(style & set, "style %08x should be set\n", set);
3467     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
3468
3469     /* a subsequent call should do nothing */
3470     SetScrollInfo(hwnd, ctl, &si, TRUE);
3471     if (style & WS_HSCROLL)
3472         ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3473     else if (style & WS_VSCROLL)
3474         ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3475     else
3476         ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3477
3478     si.fMask = SIF_PAGE;
3479     si.nPage = 5;
3480     SetScrollInfo(hwnd, ctl, &si, FALSE);
3481     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3482
3483     si.fMask = SIF_POS;
3484     si.nPos = max - 1;
3485     SetScrollInfo(hwnd, ctl, &si, FALSE);
3486     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3487
3488     si.fMask = SIF_RANGE;
3489     si.nMin = 0xdeadbeef;
3490     si.nMax = 0xdeadbeef;
3491     ret = GetScrollInfo(hwnd, ctl, &si);
3492     ok( ret, "GetScrollInfo error %d\n", GetLastError());
3493     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3494     ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
3495     ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
3496 }
3497
3498 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
3499 static void test_scroll_messages(HWND hwnd)
3500 {
3501     SCROLLINFO si;
3502     INT min, max;
3503     BOOL ret;
3504
3505     min = 0xdeadbeef;
3506     max = 0xdeadbeef;
3507     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
3508     ok( ret, "GetScrollRange error %d\n", GetLastError());
3509     if (sequence->message != WmGetScrollRangeSeq[0].message)
3510         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
3511     /* values of min and max are undefined */
3512     flush_sequence();
3513
3514     ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
3515     ok( ret, "SetScrollRange error %d\n", GetLastError());
3516     if (sequence->message != WmSetScrollRangeSeq[0].message)
3517         trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
3518     flush_sequence();
3519
3520     min = 0xdeadbeef;
3521     max = 0xdeadbeef;
3522     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
3523     ok( ret, "GetScrollRange error %d\n", GetLastError());
3524     if (sequence->message != WmGetScrollRangeSeq[0].message)
3525         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
3526     /* values of min and max are undefined */
3527     flush_sequence();
3528
3529     si.cbSize = sizeof(si);
3530     si.fMask = SIF_RANGE;
3531     si.nMin = 20;
3532     si.nMax = 160;
3533     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
3534     if (sequence->message != WmSetScrollRangeSeq[0].message)
3535         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3536     flush_sequence();
3537
3538     si.fMask = SIF_PAGE;
3539     si.nPage = 10;
3540     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
3541     if (sequence->message != WmSetScrollRangeSeq[0].message)
3542         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3543     flush_sequence();
3544
3545     si.fMask = SIF_POS;
3546     si.nPos = 20;
3547     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
3548     if (sequence->message != WmSetScrollRangeSeq[0].message)
3549         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3550     flush_sequence();
3551
3552     si.fMask = SIF_RANGE;
3553     si.nMin = 0xdeadbeef;
3554     si.nMax = 0xdeadbeef;
3555     ret = GetScrollInfo(hwnd, SB_CTL, &si);
3556     ok( ret, "GetScrollInfo error %d\n", GetLastError());
3557     if (sequence->message != WmGetScrollInfoSeq[0].message)
3558         trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3559     /* values of min and max are undefined */
3560     flush_sequence();
3561
3562     /* set WS_HSCROLL */
3563     test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
3564     /* clear WS_HSCROLL */
3565     test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
3566
3567     /* set WS_HSCROLL */
3568     test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
3569     /* clear WS_HSCROLL */
3570     test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
3571
3572     /* set WS_VSCROLL */
3573     test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
3574     /* clear WS_VSCROLL */
3575     test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
3576
3577     /* set WS_VSCROLL */
3578     test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
3579     /* clear WS_VSCROLL */
3580     test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
3581 }
3582
3583 static void test_showwindow(void)
3584 {
3585     HWND hwnd, hchild;
3586     RECT rc;
3587
3588     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
3589                            100, 100, 200, 200, 0, 0, 0, NULL);
3590     ok (hwnd != 0, "Failed to create overlapped window\n");
3591     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
3592                              0, 0, 10, 10, hwnd, 0, 0, NULL);
3593     ok (hchild != 0, "Failed to create child\n");
3594     flush_sequence();
3595
3596     /* ShowWindow( SW_SHOWNA) for invisible top level window */
3597     trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
3598     ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
3599     ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", TRUE);
3600     trace("done\n");
3601
3602     /* ShowWindow( SW_SHOWNA) for now visible top level window */
3603     trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
3604     ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
3605     ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
3606     trace("done\n");
3607     /* back to invisible */
3608     ShowWindow(hchild, SW_HIDE);
3609     ShowWindow(hwnd, SW_HIDE);
3610     flush_sequence();
3611     /* ShowWindow(SW_SHOWNA) with child and parent invisible */ 
3612     trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
3613     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
3614     ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
3615     trace("done\n");
3616     /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */ 
3617     ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
3618     flush_sequence();
3619     trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
3620     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
3621     ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
3622     trace("done\n");
3623     /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
3624     ShowWindow( hwnd, SW_SHOW);
3625     flush_sequence();
3626     trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
3627     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
3628     ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
3629     trace("done\n");
3630
3631     /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
3632     ShowWindow( hchild, SW_HIDE);
3633     flush_sequence();
3634     trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
3635     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
3636     ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
3637     trace("done\n");
3638
3639     SetCapture(hchild);
3640     ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
3641     DestroyWindow(hchild);
3642     ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
3643
3644     DestroyWindow(hwnd);
3645     flush_sequence();
3646
3647     /* Popup windows */
3648     /* Test 1:
3649      * 1. Create invisible maximized popup window.
3650      * 2. Move and resize it.
3651      * 3. Show it maximized.
3652      */
3653     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
3654     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
3655                            100, 100, 200, 200, 0, 0, 0, NULL);
3656     ok (hwnd != 0, "Failed to create popup window\n");
3657     ok(IsZoomed(hwnd), "window should be maximized\n");
3658     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
3659     trace("done\n");
3660
3661     GetWindowRect(hwnd, &rc);
3662     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
3663         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
3664         "Invalid maximized size before ShowWindow (%d,%d)-(%d,%d)\n",
3665         rc.left, rc.top, rc.right, rc.bottom);
3666     /* Reset window's size & position */
3667     SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
3668     ok(IsZoomed(hwnd), "window should be maximized\n");
3669     flush_sequence();
3670
3671     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
3672     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
3673     ok(IsZoomed(hwnd), "window should be maximized\n");
3674     ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
3675     trace("done\n");
3676
3677     GetWindowRect(hwnd, &rc);
3678     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
3679         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
3680         "Invalid maximized size after ShowWindow (%d,%d)-(%d,%d)\n",
3681         rc.left, rc.top, rc.right, rc.bottom);
3682     DestroyWindow(hwnd);
3683     flush_sequence();
3684
3685     /* Test 2:
3686      * 1. Create invisible maximized popup window.
3687      * 2. Show it maximized.
3688      */
3689     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
3690     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
3691                            100, 100, 200, 200, 0, 0, 0, NULL);
3692     ok (hwnd != 0, "Failed to create popup window\n");
3693     ok(IsZoomed(hwnd), "window should be maximized\n");
3694     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
3695     trace("done\n");
3696
3697     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
3698     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
3699     ok(IsZoomed(hwnd), "window should be maximized\n");
3700     ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
3701     trace("done\n");
3702     DestroyWindow(hwnd);
3703     flush_sequence();
3704
3705     /* Test 3:
3706      * 1. Create visible maximized popup window.
3707      */
3708     trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
3709     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
3710                            100, 100, 200, 200, 0, 0, 0, NULL);
3711     ok (hwnd != 0, "Failed to create popup window\n");
3712     ok(IsZoomed(hwnd), "window should be maximized\n");
3713     ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
3714     trace("done\n");
3715     DestroyWindow(hwnd);
3716     flush_sequence();
3717
3718     /* Test 4:
3719      * 1. Create visible popup window.
3720      * 2. Maximize it.
3721      */
3722     trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
3723     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
3724                            100, 100, 200, 200, 0, 0, 0, NULL);
3725     ok (hwnd != 0, "Failed to create popup window\n");
3726     ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
3727     ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", TRUE);
3728     trace("done\n");
3729
3730     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
3731     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
3732     ok(IsZoomed(hwnd), "window should be maximized\n");
3733     ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
3734     trace("done\n");
3735     DestroyWindow(hwnd);
3736     flush_sequence();
3737 }
3738
3739 static void test_sys_menu(void)
3740 {
3741     HWND hwnd;
3742     HMENU hmenu;
3743     UINT state;
3744
3745     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
3746                            100, 100, 200, 200, 0, 0, 0, NULL);
3747     ok (hwnd != 0, "Failed to create overlapped window\n");
3748
3749     flush_sequence();
3750
3751     /* test existing window without CS_NOCLOSE style */
3752     hmenu = GetSystemMenu(hwnd, FALSE);
3753     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
3754
3755     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
3756     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
3757     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
3758
3759     EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
3760     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
3761
3762     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
3763     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
3764     ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
3765
3766     EnableMenuItem(hmenu, SC_CLOSE, 0);
3767     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
3768
3769     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
3770     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
3771     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
3772
3773     /* test whether removing WS_SYSMENU destroys a system menu */
3774     SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
3775     SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
3776     flush_sequence();
3777     hmenu = GetSystemMenu(hwnd, FALSE);
3778     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
3779
3780     DestroyWindow(hwnd);
3781
3782     /* test new window with CS_NOCLOSE style */
3783     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
3784                            100, 100, 200, 200, 0, 0, 0, NULL);
3785     ok (hwnd != 0, "Failed to create overlapped window\n");
3786
3787     hmenu = GetSystemMenu(hwnd, FALSE);
3788     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
3789
3790     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
3791     ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
3792
3793     DestroyWindow(hwnd);
3794
3795     /* test new window without WS_SYSMENU style */
3796     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
3797                            100, 100, 200, 200, 0, 0, 0, NULL);
3798     ok(hwnd != 0, "Failed to create overlapped window\n");
3799
3800     hmenu = GetSystemMenu(hwnd, FALSE);
3801     ok(!hmenu, "GetSystemMenu error %d\n", GetLastError());
3802
3803     DestroyWindow(hwnd);
3804 }
3805
3806 /* For shown WS_OVERLAPPEDWINDOW */
3807 static const struct message WmSetIcon_1[] = {
3808     { WM_SETICON, sent },
3809     { 0x00AE, sent|defwinproc|optional }, /* XP */
3810     { WM_GETTEXT, sent|defwinproc|optional },
3811     { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
3812     { 0 }
3813 };
3814
3815 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
3816 static const struct message WmSetIcon_2[] = {
3817     { WM_SETICON, sent },
3818     { 0 }
3819 };
3820
3821 static void test_MsgWaitForMultipleObjects(HWND hwnd)
3822 {
3823     DWORD ret;
3824     MSG msg;
3825
3826     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
3827     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
3828
3829     PostMessageA(hwnd, WM_USER, 0, 0);
3830
3831     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
3832     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
3833
3834     ok(PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
3835     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
3836
3837     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
3838     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
3839
3840     PostMessageA(hwnd, WM_USER, 0, 0);
3841
3842     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
3843     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
3844
3845     ok(PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
3846     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
3847
3848     /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
3849     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
3850     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
3851
3852     PostMessageA(hwnd, WM_USER, 0, 0);
3853
3854     /* new incoming message causes it to become signaled again */
3855     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
3856     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
3857
3858     ok(PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
3859     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
3860     ok(PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
3861     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
3862 }
3863
3864 /* test if we receive the right sequence of messages */
3865 static void test_messages(void)
3866 {
3867     HWND hwnd, hparent, hchild;
3868     HWND hchild2, hbutton;
3869     HMENU hmenu;
3870     MSG msg;
3871
3872     flush_sequence();
3873
3874     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
3875                            100, 100, 200, 200, 0, 0, 0, NULL);
3876     ok (hwnd != 0, "Failed to create overlapped window\n");
3877     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
3878
3879     /* test ShowWindow(SW_HIDE) on a newly created invisible window */
3880     ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
3881     ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
3882
3883     /* test WM_SETREDRAW on a not visible top level window */
3884     test_WM_SETREDRAW(hwnd);
3885
3886     SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
3887     ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
3888     ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
3889
3890     ok(GetActiveWindow() == hwnd, "window should be active\n");
3891     ok(GetFocus() == hwnd, "window should have input focus\n");
3892     ShowWindow(hwnd, SW_HIDE);
3893     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", TRUE);
3894
3895     ShowWindow(hwnd, SW_SHOW);
3896     ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
3897
3898     ShowWindow(hwnd, SW_HIDE);
3899     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
3900
3901     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
3902     ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
3903
3904     ShowWindow(hwnd, SW_RESTORE);
3905     /* FIXME: add ok_sequence() here */
3906     flush_sequence();
3907
3908     ShowWindow(hwnd, SW_MINIMIZE);
3909     ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE);
3910     flush_sequence();
3911
3912     ShowWindow(hwnd, SW_RESTORE);
3913     /* FIXME: add ok_sequence() here */
3914     flush_sequence();
3915
3916     ShowWindow(hwnd, SW_SHOW);
3917     ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
3918
3919     ok(GetActiveWindow() == hwnd, "window should be active\n");
3920     ok(GetFocus() == hwnd, "window should have input focus\n");
3921     SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
3922     ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
3923     ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
3924     ok(GetActiveWindow() == hwnd, "window should still be active\n");
3925
3926     /* test WM_SETREDRAW on a visible top level window */
3927     ShowWindow(hwnd, SW_SHOW);
3928     test_WM_SETREDRAW(hwnd);
3929
3930     trace("testing scroll APIs on a visible top level window %p\n", hwnd);
3931     test_scroll_messages(hwnd);
3932
3933     /* test resizing and moving */
3934     SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
3935     ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
3936     flush_events();
3937     flush_sequence();
3938     SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
3939     ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
3940     flush_events();
3941     flush_sequence();
3942     SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER );
3943     ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
3944     flush_events();
3945     flush_sequence();
3946
3947     /* popups don't get WM_GETMINMAXINFO */
3948     SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
3949     SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
3950     flush_sequence();
3951     SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
3952     ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
3953
3954     DestroyWindow(hwnd);
3955     ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
3956
3957     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
3958                               100, 100, 200, 200, 0, 0, 0, NULL);
3959     ok (hparent != 0, "Failed to create parent window\n");
3960     flush_sequence();
3961
3962     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
3963                              0, 0, 10, 10, hparent, 0, 0, NULL);
3964     ok (hchild != 0, "Failed to create child window\n");
3965     ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
3966     DestroyWindow(hchild);
3967     flush_sequence();
3968
3969     /* visible child window with a caption */
3970     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
3971                              WS_CHILD | WS_VISIBLE | WS_CAPTION,
3972                              0, 0, 10, 10, hparent, 0, 0, NULL);
3973     ok (hchild != 0, "Failed to create child window\n");
3974     ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
3975
3976     trace("testing scroll APIs on a visible child window %p\n", hchild);
3977     test_scroll_messages(hchild);
3978
3979     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
3980     ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
3981
3982     DestroyWindow(hchild);
3983     flush_sequence();
3984
3985     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
3986                              0, 0, 10, 10, hparent, 0, 0, NULL);
3987     ok (hchild != 0, "Failed to create child window\n");
3988     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
3989     
3990     hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
3991                                100, 100, 50, 50, hparent, 0, 0, NULL);
3992     ok (hchild2 != 0, "Failed to create child2 window\n");
3993     flush_sequence();
3994
3995     hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
3996                               0, 100, 50, 50, hchild, 0, 0, NULL);
3997     ok (hbutton != 0, "Failed to create button window\n");
3998
3999     /* test WM_SETREDRAW on a not visible child window */
4000     test_WM_SETREDRAW(hchild);
4001
4002     ShowWindow(hchild, SW_SHOW);
4003     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4004
4005     /* check parent messages too */
4006     log_all_parent_messages++;
4007     ShowWindow(hchild, SW_HIDE);
4008     ok_sequence(WmHideChildSeq2, "ShowWindow(SW_HIDE):child", FALSE);
4009     log_all_parent_messages--;
4010
4011     ShowWindow(hchild, SW_SHOW);
4012     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4013
4014     ShowWindow(hchild, SW_HIDE);
4015     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
4016
4017     ShowWindow(hchild, SW_SHOW);
4018     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4019
4020     /* test WM_SETREDRAW on a visible child window */
4021     test_WM_SETREDRAW(hchild);
4022
4023     MoveWindow(hchild, 10, 10, 20, 20, TRUE);
4024     ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
4025
4026     ShowWindow(hchild, SW_HIDE);
4027     flush_sequence();
4028     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4029     ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
4030
4031     ShowWindow(hchild, SW_HIDE);
4032     flush_sequence();
4033     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
4034     ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
4035
4036     /* DestroyWindow sequence below expects that a child has focus */
4037     SetFocus(hchild);
4038     flush_sequence();
4039
4040     DestroyWindow(hchild);
4041     ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
4042     DestroyWindow(hchild2);
4043     DestroyWindow(hbutton);
4044
4045     flush_sequence();
4046     hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
4047                              0, 0, 100, 100, hparent, 0, 0, NULL);
4048     ok (hchild != 0, "Failed to create child popup window\n");
4049     ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
4050     DestroyWindow(hchild);
4051
4052     /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
4053     flush_sequence();
4054     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
4055                              0, 0, 100, 100, hparent, 0, 0, NULL);
4056     ok (hchild != 0, "Failed to create popup window\n");
4057     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4058     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4059     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4060     flush_sequence();
4061     ShowWindow(hchild, SW_SHOW);
4062     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4063     flush_sequence();
4064     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4065     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4066     flush_sequence();
4067     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4068     ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
4069     DestroyWindow(hchild);
4070
4071     /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
4072      * changes nothing in message sequences.
4073      */
4074     flush_sequence();
4075     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
4076                              0, 0, 100, 100, hparent, 0, 0, NULL);
4077     ok (hchild != 0, "Failed to create popup window\n");
4078     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4079     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4080     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4081     flush_sequence();
4082     ShowWindow(hchild, SW_SHOW);
4083     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4084     flush_sequence();
4085     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4086     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4087     DestroyWindow(hchild);
4088
4089     flush_sequence();
4090     hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
4091                            0, 0, 100, 100, hparent, 0, 0, NULL);
4092     ok(hwnd != 0, "Failed to create custom dialog window\n");
4093     ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
4094
4095     /*
4096     trace("testing scroll APIs on a visible dialog %p\n", hwnd);
4097     test_scroll_messages(hwnd);
4098     */
4099
4100     flush_sequence();
4101
4102     test_def_id = 1;
4103     SendMessage(hwnd, WM_NULL, 0, 0);
4104
4105     flush_sequence();
4106     after_end_dialog = 1;
4107     EndDialog( hwnd, 0 );
4108     ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
4109
4110     DestroyWindow(hwnd);
4111     after_end_dialog = 0;
4112     test_def_id = 0;
4113
4114     hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP,
4115                            0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
4116     ok(hwnd != 0, "Failed to create custom dialog window\n");
4117     flush_sequence();
4118     trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
4119     ShowWindow(hwnd, SW_SHOW);
4120     ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
4121     DestroyWindow(hwnd);
4122
4123     flush_sequence();
4124     DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
4125     ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
4126
4127     DestroyWindow(hparent);
4128     flush_sequence();
4129
4130     /* Message sequence for SetMenu */
4131     ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a window without a menu\n");
4132     ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
4133
4134     hmenu = CreateMenu();
4135     ok (hmenu != 0, "Failed to create menu\n");
4136     ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
4137     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4138                            100, 100, 200, 200, 0, hmenu, 0, NULL);
4139     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4140     ok (SetMenu(hwnd, 0), "SetMenu\n");
4141     ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
4142     ok (SetMenu(hwnd, 0), "SetMenu\n");
4143     ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
4144     ShowWindow(hwnd, SW_SHOW);
4145     UpdateWindow( hwnd );
4146     flush_events();
4147     flush_sequence();
4148     ok (SetMenu(hwnd, 0), "SetMenu\n");
4149     ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
4150     ok (SetMenu(hwnd, hmenu), "SetMenu\n");
4151     ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
4152
4153     UpdateWindow( hwnd );
4154     flush_events();
4155     flush_sequence();
4156     ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
4157     flush_events();
4158     ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
4159
4160     DestroyWindow(hwnd);
4161     flush_sequence();
4162
4163     /* Message sequence for EnableWindow */
4164     hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4165                               100, 100, 200, 200, 0, 0, 0, NULL);
4166     ok (hparent != 0, "Failed to create parent window\n");
4167     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
4168                              0, 0, 10, 10, hparent, 0, 0, NULL);
4169     ok (hchild != 0, "Failed to create child window\n");
4170
4171     SetFocus(hchild);
4172     flush_events();
4173     flush_sequence();
4174
4175     EnableWindow(hparent, FALSE);
4176     ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
4177
4178     EnableWindow(hparent, TRUE);
4179     ok_sequence(WmEnableWindowSeq_2, "EnableWindow(TRUE)", FALSE);
4180
4181     flush_events();
4182     flush_sequence();
4183
4184     test_MsgWaitForMultipleObjects(hparent);
4185
4186     /* the following test causes an exception in user.exe under win9x */
4187     if (!PostMessageW( hparent, WM_USER, 0, 0 ))
4188     {
4189         DestroyWindow(hparent);
4190         flush_sequence();
4191         return;
4192     }
4193     PostMessageW( hparent, WM_USER+1, 0, 0 );
4194     /* PeekMessage(NULL) fails, but still removes the message */
4195     SetLastError(0xdeadbeef);
4196     ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
4197     ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
4198         GetLastError() == 0xdeadbeef, /* NT4 */
4199         "last error is %d\n", GetLastError() );
4200     ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
4201     ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
4202
4203     DestroyWindow(hchild);
4204     DestroyWindow(hparent);
4205     flush_sequence();
4206
4207     /* Message sequences for WM_SETICON */
4208     trace("testing WM_SETICON\n");
4209     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4210                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4211                            NULL, NULL, 0);
4212     ShowWindow(hwnd, SW_SHOW);
4213     UpdateWindow(hwnd);
4214     flush_events();
4215     flush_sequence();
4216     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4217     ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
4218
4219     ShowWindow(hwnd, SW_HIDE);
4220     flush_events();
4221     flush_sequence();
4222     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4223     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window with caption", FALSE);
4224     DestroyWindow(hwnd);
4225     flush_sequence();
4226
4227     hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
4228                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4229                            NULL, NULL, 0);
4230     ShowWindow(hwnd, SW_SHOW);
4231     UpdateWindow(hwnd);
4232     flush_events();
4233     flush_sequence();
4234     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4235     ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
4236
4237     ShowWindow(hwnd, SW_HIDE);
4238     flush_events();
4239     flush_sequence();
4240     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4241     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
4242     DestroyWindow(hwnd);
4243     flush_sequence();
4244 }
4245
4246 static void invisible_parent_tests(void)
4247 {
4248     HWND hparent, hchild;
4249
4250     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
4251                               100, 100, 200, 200, 0, 0, 0, NULL);
4252     ok (hparent != 0, "Failed to create parent window\n");
4253     flush_sequence();
4254
4255     /* test showing child with hidden parent */
4256
4257     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4258                              0, 0, 10, 10, hparent, 0, 0, NULL);
4259     ok (hchild != 0, "Failed to create child window\n");
4260     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4261
4262     ShowWindow( hchild, SW_MINIMIZE );
4263     ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4264     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4265     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4266
4267     /* repeat */
4268     flush_events();
4269     flush_sequence();
4270     ShowWindow( hchild, SW_MINIMIZE );
4271     ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4272
4273     DestroyWindow(hchild);
4274     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4275                              0, 0, 10, 10, hparent, 0, 0, NULL);
4276     flush_sequence();
4277
4278     ShowWindow( hchild, SW_MAXIMIZE );
4279     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
4280     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4281     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4282
4283     /* repeat */
4284     flush_events();
4285     flush_sequence();
4286     ShowWindow( hchild, SW_MAXIMIZE );
4287     ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
4288
4289     DestroyWindow(hchild);
4290     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4291                              0, 0, 10, 10, hparent, 0, 0, NULL);
4292     flush_sequence();
4293
4294     ShowWindow( hchild, SW_RESTORE );
4295     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
4296     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4297     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4298
4299     DestroyWindow(hchild);
4300     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4301                              0, 0, 10, 10, hparent, 0, 0, NULL);
4302     flush_sequence();
4303
4304     ShowWindow( hchild, SW_SHOWMINIMIZED );
4305     ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
4306     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4307     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4308
4309     /* repeat */
4310     flush_events();
4311     flush_sequence();
4312     ShowWindow( hchild, SW_SHOWMINIMIZED );
4313     ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
4314
4315     DestroyWindow(hchild);
4316     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4317                              0, 0, 10, 10, hparent, 0, 0, NULL);
4318     flush_sequence();
4319
4320     /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
4321     ShowWindow( hchild, SW_SHOWMAXIMIZED );
4322     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
4323     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
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_SHOWMINNOACTIVE );
4332     ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) 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_SHOWMINNOACTIVE );
4340     ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) 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     /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
4348     ShowWindow( hchild, SW_FORCEMINIMIZE );
4349     ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
4350 todo_wine {
4351     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
4352 }
4353     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4354
4355     DestroyWindow(hchild);
4356     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4357                              0, 0, 10, 10, hparent, 0, 0, NULL);
4358     flush_sequence();
4359
4360     ShowWindow( hchild, SW_SHOWNA );
4361     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
4362     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4363     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4364
4365     /* repeat */
4366     flush_events();
4367     flush_sequence();
4368     ShowWindow( hchild, SW_SHOWNA );
4369     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
4370
4371     DestroyWindow(hchild);
4372     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4373                              0, 0, 10, 10, hparent, 0, 0, NULL);
4374     flush_sequence();
4375
4376     ShowWindow( hchild, SW_SHOW );
4377     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
4378     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4379     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4380
4381     /* repeat */
4382     flush_events();
4383     flush_sequence();
4384     ShowWindow( hchild, SW_SHOW );
4385     ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
4386
4387     ShowWindow( hchild, SW_HIDE );
4388     ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
4389     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
4390     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4391
4392     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4393     ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
4394     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4395     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4396
4397     SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4398     ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
4399     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
4400     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4401
4402     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4403     flush_sequence();
4404     DestroyWindow(hchild);
4405     ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
4406
4407     DestroyWindow(hparent);
4408     flush_sequence();
4409 }
4410
4411 /****************** button message test *************************/
4412 static const struct message WmSetFocusButtonSeq[] =
4413 {
4414     { HCBT_SETFOCUS, hook },
4415     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
4416     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4417     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4418     { WM_SETFOCUS, sent|wparam, 0 },
4419     { WM_CTLCOLORBTN, sent|defwinproc },
4420     { 0 }
4421 };
4422 static const struct message WmKillFocusButtonSeq[] =
4423 {
4424     { HCBT_SETFOCUS, hook },
4425     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4426     { WM_KILLFOCUS, sent|wparam, 0 },
4427     { WM_CTLCOLORBTN, sent|defwinproc },
4428     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
4429     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
4430     { 0 }
4431 };
4432 static const struct message WmSetFocusStaticSeq[] =
4433 {
4434     { HCBT_SETFOCUS, hook },
4435     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
4436     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4437     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4438     { WM_SETFOCUS, sent|wparam, 0 },
4439     { WM_CTLCOLORSTATIC, sent|defwinproc },
4440     { 0 }
4441 };
4442 static const struct message WmKillFocusStaticSeq[] =
4443 {
4444     { HCBT_SETFOCUS, hook },
4445     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4446     { WM_KILLFOCUS, sent|wparam, 0 },
4447     { WM_CTLCOLORSTATIC, sent|defwinproc },
4448     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
4449     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
4450     { 0 }
4451 };
4452 static const struct message WmLButtonDownSeq[] =
4453 {
4454     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
4455     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
4456     { HCBT_SETFOCUS, hook },
4457     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
4458     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4459     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4460     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
4461     { WM_CTLCOLORBTN, sent|defwinproc },
4462     { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
4463     { WM_CTLCOLORBTN, sent|defwinproc },
4464     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4465     { 0 }
4466 };
4467 static const struct message WmLButtonUpSeq[] =
4468 {
4469     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
4470     { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
4471     { WM_CTLCOLORBTN, sent|defwinproc },
4472     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4473     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
4474     { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
4475     { 0 }
4476 };
4477 static const struct message WmSetFontButtonSeq[] =
4478 {
4479     { WM_SETFONT, sent },
4480     { WM_PAINT, sent },
4481     { WM_ERASEBKGND, sent|defwinproc|optional },
4482     { WM_CTLCOLORBTN, sent|defwinproc },
4483     { 0 }
4484 };
4485
4486 static WNDPROC old_button_proc;
4487
4488 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4489 {
4490     static long defwndproc_counter = 0;
4491     LRESULT ret;
4492     struct message msg;
4493
4494     trace("button: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
4495
4496     /* explicitly ignore WM_GETICON message */
4497     if (message == WM_GETICON) return 0;
4498
4499     msg.message = message;
4500     msg.flags = sent|wparam|lparam;
4501     if (defwndproc_counter) msg.flags |= defwinproc;
4502     msg.wParam = wParam;
4503     msg.lParam = lParam;
4504     add_message(&msg);
4505
4506     if (message == BM_SETSTATE)
4507         ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
4508
4509     defwndproc_counter++;
4510     ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
4511     defwndproc_counter--;
4512
4513     return ret;
4514 }
4515
4516 static void subclass_button(void)
4517 {
4518     WNDCLASSA cls;
4519
4520     if (!GetClassInfoA(0, "button", &cls)) assert(0);
4521
4522     old_button_proc = cls.lpfnWndProc;
4523
4524     cls.hInstance = GetModuleHandle(0);
4525     cls.lpfnWndProc = button_hook_proc;
4526     cls.lpszClassName = "my_button_class";
4527     UnregisterClass(cls.lpszClassName, cls.hInstance);
4528     if (!RegisterClassA(&cls)) assert(0);
4529 }
4530
4531 static void test_button_messages(void)
4532 {
4533     static const struct
4534     {
4535         DWORD style;
4536         DWORD dlg_code;
4537         const struct message *setfocus;
4538         const struct message *killfocus;
4539     } button[] = {
4540         { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
4541           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
4542         { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
4543           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
4544         { BS_CHECKBOX, DLGC_BUTTON,
4545           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4546         { BS_AUTOCHECKBOX, DLGC_BUTTON,
4547           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4548         { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
4549           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4550         { BS_3STATE, DLGC_BUTTON,
4551           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4552         { BS_AUTO3STATE, DLGC_BUTTON,
4553           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4554         { BS_GROUPBOX, DLGC_STATIC,
4555           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4556         { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
4557           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
4558         { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
4559           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4560         { BS_OWNERDRAW, DLGC_BUTTON,
4561           WmSetFocusButtonSeq, WmKillFocusButtonSeq }
4562     };
4563     unsigned int i;
4564     HWND hwnd;
4565     DWORD dlg_code;
4566     HFONT zfont;
4567
4568     subclass_button();
4569
4570     for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
4571     {
4572         hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP,
4573                                0, 0, 50, 14, 0, 0, 0, NULL);
4574         ok(hwnd != 0, "Failed to create button window\n");
4575
4576         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
4577         ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
4578
4579         ShowWindow(hwnd, SW_SHOW);
4580         UpdateWindow(hwnd);
4581         SetFocus(0);
4582         flush_sequence();
4583
4584         trace("button style %08x\n", button[i].style);
4585         SetFocus(hwnd);
4586         ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
4587
4588         SetFocus(0);
4589         ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
4590
4591         DestroyWindow(hwnd);
4592     }
4593
4594     hwnd = CreateWindowExA(0, "my_button_class", "test", BS_PUSHBUTTON | WS_POPUP | WS_VISIBLE,
4595                            0, 0, 50, 14, 0, 0, 0, NULL);
4596     ok(hwnd != 0, "Failed to create button window\n");
4597
4598     SetFocus(0);
4599     flush_events();
4600     flush_sequence();
4601
4602     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
4603     ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
4604
4605     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
4606     ok_sequence(WmLButtonUpSeq, "WM_LBUTTONUP on a button", FALSE);
4607
4608     flush_sequence();
4609     zfont = (HFONT)GetStockObject(SYSTEM_FONT);
4610     SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
4611     UpdateWindow(hwnd);
4612     ok_sequence(WmSetFontButtonSeq, "WM_SETFONT on a button", FALSE);
4613
4614     DestroyWindow(hwnd);
4615 }
4616
4617 /****************** static message test *************************/
4618 static const struct message WmSetFontStaticSeq[] =
4619 {
4620     { WM_SETFONT, sent },
4621     { WM_PAINT, sent|defwinproc },
4622     { WM_ERASEBKGND, sent|defwinproc|optional },
4623     { WM_CTLCOLORSTATIC, sent|defwinproc },
4624     { 0 }
4625 };
4626
4627 static WNDPROC old_static_proc;
4628
4629 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4630 {
4631     static long defwndproc_counter = 0;
4632     LRESULT ret;
4633     struct message msg;
4634
4635     trace("static: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
4636
4637     /* explicitly ignore WM_GETICON message */
4638     if (message == WM_GETICON) return 0;
4639
4640     msg.message = message;
4641     msg.flags = sent|wparam|lparam;
4642     if (defwndproc_counter) msg.flags |= defwinproc;
4643     msg.wParam = wParam;
4644     msg.lParam = lParam;
4645     add_message(&msg);
4646
4647
4648     defwndproc_counter++;
4649     ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
4650     defwndproc_counter--;
4651
4652     return ret;
4653 }
4654
4655 static void subclass_static(void)
4656 {
4657     WNDCLASSA cls;
4658
4659     if (!GetClassInfoA(0, "static", &cls)) assert(0);
4660
4661     old_static_proc = cls.lpfnWndProc;
4662
4663     cls.hInstance = GetModuleHandle(0);
4664     cls.lpfnWndProc = static_hook_proc;
4665     cls.lpszClassName = "my_static_class";
4666     UnregisterClass(cls.lpszClassName, cls.hInstance);
4667     if (!RegisterClassA(&cls)) assert(0);
4668 }
4669
4670 static void test_static_messages(void)
4671 {
4672     /* FIXME: make as comprehensive as the button message test */
4673     static const struct
4674     {
4675         DWORD style;
4676         DWORD dlg_code;
4677         const struct message *setfont;
4678     } static_ctrl[] = {
4679         { SS_LEFT, DLGC_STATIC,
4680           WmSetFontStaticSeq }
4681     };
4682     unsigned int i;
4683     HWND hwnd;
4684     DWORD dlg_code;
4685
4686     subclass_static();
4687
4688     for (i = 0; i < sizeof(static_ctrl)/sizeof(static_ctrl[0]); i++)
4689     {
4690         hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
4691                                0, 0, 50, 14, 0, 0, 0, NULL);
4692         ok(hwnd != 0, "Failed to create static window\n");
4693
4694         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
4695         ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
4696
4697         ShowWindow(hwnd, SW_SHOW);
4698         UpdateWindow(hwnd);
4699         SetFocus(0);
4700         flush_sequence();
4701
4702         trace("static style %08x\n", static_ctrl[i].style);
4703         SendMessage(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
4704         ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
4705
4706         DestroyWindow(hwnd);
4707     }
4708 }
4709
4710 /************* painting message test ********************/
4711
4712 void dump_region(HRGN hrgn)
4713 {
4714     DWORD i, size;
4715     RGNDATA *data = NULL;
4716     RECT *rect;
4717
4718     if (!hrgn)
4719     {
4720         printf( "null region\n" );
4721         return;
4722     }
4723     if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
4724     if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
4725     GetRegionData( hrgn, size, data );
4726     printf("%d rects:", data->rdh.nCount );
4727     for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
4728         printf( " (%d,%d)-(%d,%d)", rect->left, rect->top, rect->right, rect->bottom );
4729     printf("\n");
4730     HeapFree( GetProcessHeap(), 0, data );
4731 }
4732
4733 static void check_update_rgn( HWND hwnd, HRGN hrgn )
4734 {
4735     INT ret;
4736     RECT r1, r2;
4737     HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
4738     HRGN update = CreateRectRgn( 0, 0, 0, 0 );
4739
4740     ret = GetUpdateRgn( hwnd, update, FALSE );
4741     ok( ret != ERROR, "GetUpdateRgn failed\n" );
4742     if (ret == NULLREGION)
4743     {
4744         ok( !hrgn, "Update region shouldn't be empty\n" );
4745     }
4746     else
4747     {
4748         if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
4749         {
4750             ok( 0, "Regions are different\n" );
4751             if (winetest_debug > 0)
4752             {
4753                 printf( "Update region: " );
4754                 dump_region( update );
4755                 printf( "Wanted region: " );
4756                 dump_region( hrgn );
4757             }
4758         }
4759     }
4760     GetRgnBox( update, &r1 );
4761     GetUpdateRect( hwnd, &r2, FALSE );
4762     ok( r1.left == r2.left && r1.top == r2.top && r1.right == r2.right && r1.bottom == r2.bottom,
4763         "Rectangles are different: %d,%d-%d,%d / %d,%d-%d,%d\n",
4764         r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom );
4765
4766     DeleteObject( tmp );
4767     DeleteObject( update );
4768 }
4769
4770 static const struct message WmInvalidateRgn[] = {
4771     { WM_NCPAINT, sent },
4772     { WM_GETTEXT, sent|defwinproc|optional },
4773     { 0 }
4774 };
4775
4776 static const struct message WmGetUpdateRect[] = {
4777     { WM_NCPAINT, sent },
4778     { WM_GETTEXT, sent|defwinproc|optional },
4779     { WM_PAINT, sent },
4780     { 0 }
4781 };
4782
4783 static const struct message WmInvalidateFull[] = {
4784     { WM_NCPAINT, sent|wparam, 1 },
4785     { WM_GETTEXT, sent|defwinproc|optional },
4786     { 0 }
4787 };
4788
4789 static const struct message WmInvalidateErase[] = {
4790     { WM_NCPAINT, sent|wparam, 1 },
4791     { WM_GETTEXT, sent|defwinproc|optional },
4792     { WM_ERASEBKGND, sent },
4793     { 0 }
4794 };
4795
4796 static const struct message WmInvalidatePaint[] = {
4797     { WM_PAINT, sent },
4798     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
4799     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4800     { 0 }
4801 };
4802
4803 static const struct message WmInvalidateErasePaint[] = {
4804     { WM_PAINT, sent },
4805     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
4806     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4807     { WM_ERASEBKGND, sent|beginpaint },
4808     { 0 }
4809 };
4810
4811 static const struct message WmInvalidateErasePaint2[] = {
4812     { WM_PAINT, sent },
4813     { WM_NCPAINT, sent|beginpaint },
4814     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4815     { WM_ERASEBKGND, sent|beginpaint },
4816     { 0 }
4817 };
4818
4819 static const struct message WmErase[] = {
4820     { WM_ERASEBKGND, sent },
4821     { 0 }
4822 };
4823
4824 static const struct message WmPaint[] = {
4825     { WM_PAINT, sent },
4826     { 0 }
4827 };
4828
4829 static const struct message WmParentOnlyPaint[] = {
4830     { WM_PAINT, sent|parent },
4831     { 0 }
4832 };
4833
4834 static const struct message WmInvalidateParent[] = {
4835     { WM_NCPAINT, sent|parent },
4836     { WM_GETTEXT, sent|defwinproc|parent|optional },
4837     { WM_ERASEBKGND, sent|parent },
4838     { 0 }
4839 };
4840
4841 static const struct message WmInvalidateParentChild[] = {
4842     { WM_NCPAINT, sent|parent },
4843     { WM_GETTEXT, sent|defwinproc|parent|optional },
4844     { WM_ERASEBKGND, sent|parent },
4845     { WM_NCPAINT, sent },
4846     { WM_GETTEXT, sent|defwinproc|optional },
4847     { WM_ERASEBKGND, sent },
4848     { 0 }
4849 };
4850
4851 static const struct message WmInvalidateParentChild2[] = {
4852     { WM_ERASEBKGND, sent|parent },
4853     { WM_NCPAINT, sent },
4854     { WM_GETTEXT, sent|defwinproc|optional },
4855     { WM_ERASEBKGND, sent },
4856     { 0 }
4857 };
4858
4859 static const struct message WmParentPaint[] = {
4860     { WM_PAINT, sent|parent },
4861     { WM_PAINT, sent },
4862     { 0 }
4863 };
4864
4865 static const struct message WmParentPaintNc[] = {
4866     { WM_PAINT, sent|parent },
4867     { WM_PAINT, sent },
4868     { WM_NCPAINT, sent|beginpaint },
4869     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4870     { WM_ERASEBKGND, sent|beginpaint },
4871     { 0 }
4872 };
4873
4874 static const struct message WmChildPaintNc[] = {
4875     { WM_PAINT, sent },
4876     { WM_NCPAINT, sent|beginpaint },
4877     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4878     { WM_ERASEBKGND, sent|beginpaint },
4879     { 0 }
4880 };
4881
4882 static const struct message WmParentErasePaint[] = {
4883     { WM_PAINT, sent|parent },
4884     { WM_NCPAINT, sent|parent|beginpaint },
4885     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
4886     { WM_ERASEBKGND, sent|parent|beginpaint },
4887     { WM_PAINT, sent },
4888     { WM_NCPAINT, sent|beginpaint },
4889     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4890     { WM_ERASEBKGND, sent|beginpaint },
4891     { 0 }
4892 };
4893
4894 static const struct message WmParentOnlyNcPaint[] = {
4895     { WM_PAINT, sent|parent },
4896     { WM_NCPAINT, sent|parent|beginpaint },
4897     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
4898     { 0 }
4899 };
4900
4901 static const struct message WmSetParentStyle[] = {
4902     { WM_STYLECHANGING, sent|parent },
4903     { WM_STYLECHANGED, sent|parent },
4904     { 0 }
4905 };
4906
4907 static void test_paint_messages(void)
4908 {
4909     BOOL ret;
4910     RECT rect;
4911     POINT pt;
4912     MSG msg;
4913     HWND hparent, hchild;
4914     HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
4915     HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
4916     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4917                                 100, 100, 200, 200, 0, 0, 0, NULL);
4918     ok (hwnd != 0, "Failed to create overlapped window\n");
4919
4920     ShowWindow( hwnd, SW_SHOW );
4921     UpdateWindow( hwnd );
4922     flush_events();
4923     flush_sequence();
4924
4925     check_update_rgn( hwnd, 0 );
4926     SetRectRgn( hrgn, 10, 10, 20, 20 );
4927     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
4928     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
4929     check_update_rgn( hwnd, hrgn );
4930     SetRectRgn( hrgn2, 20, 20, 30, 30 );
4931     ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
4932     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
4933     CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
4934     check_update_rgn( hwnd, hrgn );
4935     /* validate everything */
4936     ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
4937     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
4938     check_update_rgn( hwnd, 0 );
4939
4940     /* test empty region */
4941     SetRectRgn( hrgn, 10, 10, 10, 15 );
4942     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
4943     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
4944     check_update_rgn( hwnd, 0 );
4945     /* test empty rect */
4946     SetRect( &rect, 10, 10, 10, 15 );
4947     ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
4948     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
4949     check_update_rgn( hwnd, 0 );
4950
4951     /* flush pending messages */
4952     flush_events();
4953     flush_sequence();
4954
4955     GetClientRect( hwnd, &rect );
4956     SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
4957     /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
4958      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
4959      */
4960     trace("testing InvalidateRect(0, NULL, FALSE)\n");
4961     SetRectEmpty( &rect );
4962     ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) should fail\n");
4963     check_update_rgn( hwnd, hrgn );
4964     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
4965     flush_events();
4966     ok_sequence( WmPaint, "Paint", FALSE );
4967     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
4968     check_update_rgn( hwnd, 0 );
4969
4970     /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
4971      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
4972      */
4973     trace("testing ValidateRect(0, NULL)\n");
4974     SetRectEmpty( &rect );
4975     ok(ValidateRect(0, &rect), "ValidateRect(0, &rc) should not fail\n");
4976     check_update_rgn( hwnd, hrgn );
4977     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
4978     flush_events();
4979     ok_sequence( WmPaint, "Paint", FALSE );
4980     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
4981     check_update_rgn( hwnd, 0 );
4982
4983     trace("testing InvalidateRgn(0, NULL, FALSE)\n");
4984     SetLastError(0xdeadbeef);
4985     ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
4986     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error code %d\n", GetLastError());
4987     check_update_rgn( hwnd, 0 );
4988     flush_events();
4989     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
4990
4991     trace("testing ValidateRgn(0, NULL)\n");
4992     SetLastError(0xdeadbeef);
4993     ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
4994     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error code %d\n", GetLastError());
4995     check_update_rgn( hwnd, 0 );
4996     flush_events();
4997     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
4998
4999     /* now with frame */
5000     SetRectRgn( hrgn, -5, -5, 20, 20 );
5001
5002     /* flush pending messages */
5003     flush_events();
5004     flush_sequence();
5005     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5006     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
5007
5008     SetRectRgn( hrgn, 0, 0, 20, 20 );  /* GetUpdateRgn clips to client area */
5009     check_update_rgn( hwnd, hrgn );
5010
5011     flush_sequence();
5012     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
5013     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
5014
5015     flush_sequence();
5016     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
5017     ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
5018
5019     GetClientRect( hwnd, &rect );
5020     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
5021     check_update_rgn( hwnd, hrgn );
5022
5023     flush_sequence();
5024     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
5025     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5026
5027     flush_sequence();
5028     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
5029     ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
5030     check_update_rgn( hwnd, 0 );
5031
5032     flush_sequence();
5033     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
5034     ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
5035     check_update_rgn( hwnd, 0 );
5036
5037     flush_sequence();
5038     SetRectRgn( hrgn, 0, 0, 100, 100 );
5039     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5040     SetRectRgn( hrgn, 0, 0, 50, 100 );
5041     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
5042     SetRectRgn( hrgn, 50, 0, 100, 100 );
5043     check_update_rgn( hwnd, hrgn );
5044     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
5045     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );  /* must not generate messages, everything is valid */
5046     check_update_rgn( hwnd, 0 );
5047
5048     flush_sequence();
5049     SetRectRgn( hrgn, 0, 0, 100, 100 );
5050     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
5051     SetRectRgn( hrgn, 0, 0, 100, 50 );
5052     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
5053     ok_sequence( WmErase, "Erase", FALSE );
5054     SetRectRgn( hrgn, 0, 50, 100, 100 );
5055     check_update_rgn( hwnd, hrgn );
5056
5057     flush_sequence();
5058     SetRectRgn( hrgn, 0, 0, 100, 100 );
5059     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
5060     SetRectRgn( hrgn, 0, 0, 50, 50 );
5061     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
5062     ok_sequence( WmPaint, "Paint", FALSE );
5063
5064     flush_sequence();
5065     SetRectRgn( hrgn, -4, -4, -2, -2 );
5066     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5067     SetRectRgn( hrgn, -200, -200, -198, -198 );
5068     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
5069     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
5070
5071     flush_sequence();
5072     SetRectRgn( hrgn, -4, -4, -2, -2 );
5073     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5074     SetRectRgn( hrgn, -4, -4, -3, -3 );
5075     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
5076     SetRectRgn( hrgn, 0, 0, 1, 1 );
5077     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
5078     ok_sequence( WmPaint, "Paint", FALSE );
5079
5080     flush_sequence();
5081     SetRectRgn( hrgn, -4, -4, -1, -1 );
5082     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5083     RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
5084     /* make sure no WM_PAINT was generated */
5085     flush_events();
5086     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
5087
5088     flush_sequence();
5089     SetRectRgn( hrgn, -4, -4, -1, -1 );
5090     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5091     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
5092     {
5093         if (msg.hwnd == hwnd && msg.message == WM_PAINT)
5094         {
5095             /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
5096             INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
5097             ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
5098             ret = GetUpdateRect( hwnd, &rect, FALSE );
5099             ok( ret, "Invalid GetUpdateRect result %d\n", ret );
5100             /* this will send WM_NCPAINT and validate the non client area */
5101             ret = GetUpdateRect( hwnd, &rect, TRUE );
5102             ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
5103         }
5104         DispatchMessage( &msg );
5105     }
5106     ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
5107
5108     DestroyWindow( hwnd );
5109
5110     /* now test with a child window */
5111
5112     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
5113                               100, 100, 200, 200, 0, 0, 0, NULL);
5114     ok (hparent != 0, "Failed to create parent window\n");
5115
5116     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
5117                            10, 10, 100, 100, hparent, 0, 0, NULL);
5118     ok (hchild != 0, "Failed to create child window\n");
5119
5120     ShowWindow( hparent, SW_SHOW );
5121     UpdateWindow( hparent );
5122     UpdateWindow( hchild );
5123     flush_events();
5124     flush_sequence();
5125     log_all_parent_messages++;
5126
5127     SetRect( &rect, 0, 0, 50, 50 );
5128     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5129     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
5130     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
5131
5132     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5133     pt.x = pt.y = 0;
5134     MapWindowPoints( hchild, hparent, &pt, 1 );
5135     SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
5136     check_update_rgn( hchild, hrgn );
5137     SetRectRgn( hrgn, 0, 0, 50, 50 );
5138     check_update_rgn( hparent, hrgn );
5139     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5140     ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
5141     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
5142     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
5143
5144     flush_events();
5145     ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
5146
5147     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
5148     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5149     ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
5150     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
5151     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
5152
5153     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
5154     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
5155     ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
5156
5157     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
5158     flush_sequence();
5159     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
5160     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5161     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
5162
5163     /* flush all paint messages */
5164     flush_events();
5165     flush_sequence();
5166
5167     /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
5168     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
5169     SetRectRgn( hrgn, 0, 0, 50, 50 );
5170     check_update_rgn( hparent, hrgn );
5171     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
5172     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5173     SetRectRgn( hrgn, 0, 0, 50, 50 );
5174     check_update_rgn( hparent, hrgn );
5175
5176     /* flush all paint messages */
5177     flush_events();
5178     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
5179     flush_sequence();
5180
5181     /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
5182     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5183     SetRectRgn( hrgn, 0, 0, 50, 50 );
5184     check_update_rgn( hparent, hrgn );
5185     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
5186     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5187     SetRectRgn( hrgn2, 10, 10, 50, 50 );
5188     CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
5189     check_update_rgn( hparent, hrgn );
5190     /* flush all paint messages */
5191     flush_events();
5192     flush_sequence();
5193
5194     /* same as above but parent gets completely validated */
5195     SetRect( &rect, 20, 20, 30, 30 );
5196     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5197     SetRectRgn( hrgn, 20, 20, 30, 30 );
5198     check_update_rgn( hparent, hrgn );
5199     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
5200     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5201     check_update_rgn( hparent, 0 );  /* no update region */
5202     flush_events();
5203     ok_sequence( WmEmptySeq, "WmEmpty", FALSE );  /* and no paint messages */
5204
5205     /* make sure RDW_VALIDATE on child doesn't have the same effect */
5206     flush_sequence();
5207     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5208     SetRectRgn( hrgn, 20, 20, 30, 30 );
5209     check_update_rgn( hparent, hrgn );
5210     RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
5211     SetRectRgn( hrgn, 20, 20, 30, 30 );
5212     check_update_rgn( hparent, hrgn );
5213
5214     /* same as above but normal WM_PAINT doesn't validate parent */
5215     flush_sequence();
5216     SetRect( &rect, 20, 20, 30, 30 );
5217     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5218     SetRectRgn( hrgn, 20, 20, 30, 30 );
5219     check_update_rgn( hparent, hrgn );
5220     /* no WM_PAINT in child while parent still pending */
5221     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5222     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
5223     while (PeekMessage( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5224     ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
5225
5226     flush_sequence();
5227     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5228     /* no WM_PAINT in child while parent still pending */
5229     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5230     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
5231     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
5232     /* now that parent is valid child should get WM_PAINT */
5233     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5234     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5235     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5236     ok_sequence( WmEmptySeq, "No other message", FALSE );
5237
5238     /* same thing with WS_CLIPCHILDREN in parent */
5239     flush_sequence();
5240     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
5241     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
5242     /* changing style invalidates non client area, but we need to invalidate something else to see it */
5243     RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
5244     ok_sequence( WmEmptySeq, "No message", FALSE );
5245     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
5246     ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
5247
5248     flush_sequence();
5249     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
5250     SetRectRgn( hrgn, 20, 20, 30, 30 );
5251     check_update_rgn( hparent, hrgn );
5252     /* no WM_PAINT in child while parent still pending */
5253     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5254     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
5255     /* WM_PAINT in parent first */
5256     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5257     ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
5258
5259     /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
5260     flush_sequence();
5261     SetRect( &rect, 0, 0, 30, 30 );
5262     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
5263     SetRectRgn( hrgn, 0, 0, 30, 30 );
5264     check_update_rgn( hparent, hrgn );
5265     flush_events();
5266     ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
5267
5268     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
5269     flush_sequence();
5270     SetRect( &rect, -10, 0, 30, 30 );
5271     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
5272     SetRect( &rect, 0, 0, 20, 20 );
5273     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
5274     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
5275     ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
5276
5277     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
5278     flush_sequence();
5279     SetRect( &rect, -10, 0, 30, 30 );
5280     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
5281     SetRect( &rect, 0, 0, 100, 100 );
5282     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
5283     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
5284     ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
5285     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5286     ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
5287
5288     /* test RDW_INTERNALPAINT behavior */
5289
5290     flush_sequence();
5291     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
5292     flush_events();
5293     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
5294
5295     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
5296     flush_events();
5297     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
5298
5299     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
5300     flush_events();
5301     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
5302
5303     assert( GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
5304     UpdateWindow( hparent );
5305     flush_events();
5306     flush_sequence();
5307     trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
5308     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5309     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
5310                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5311     flush_events();
5312     ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
5313
5314     UpdateWindow( hparent );
5315     flush_events();
5316     flush_sequence();
5317     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
5318     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5319     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
5320                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5321     flush_events();
5322     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
5323
5324     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
5325     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
5326     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
5327     flush_events();
5328     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
5329
5330     assert( !(GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
5331     UpdateWindow( hparent );
5332     flush_events();
5333     flush_sequence();
5334     trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
5335     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5336     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
5337                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5338     flush_events();
5339     ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
5340
5341     UpdateWindow( hparent );
5342     flush_events();
5343     flush_sequence();
5344     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
5345     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5346     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
5347                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5348     flush_events();
5349     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
5350
5351     log_all_parent_messages--;
5352     DestroyWindow( hparent );
5353     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
5354
5355     DeleteObject( hrgn );
5356     DeleteObject( hrgn2 );
5357 }
5358
5359 struct wnd_event
5360 {
5361     HWND hwnd;
5362     HANDLE event;
5363 };
5364
5365 static DWORD WINAPI thread_proc(void *param)
5366 {
5367     MSG msg;
5368     struct wnd_event *wnd_event = (struct wnd_event *)param;
5369
5370     wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
5371                                       100, 100, 200, 200, 0, 0, 0, NULL);
5372     ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
5373
5374     SetEvent(wnd_event->event);
5375
5376     while (GetMessage(&msg, 0, 0, 0))
5377     {
5378         TranslateMessage(&msg);
5379         DispatchMessage(&msg);
5380     }
5381
5382     ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
5383
5384     return 0;
5385 }
5386
5387 static void test_interthread_messages(void)
5388 {
5389     HANDLE hThread;
5390     DWORD tid;
5391     WNDPROC proc;
5392     MSG msg;
5393     char buf[256];
5394     int len, expected_len;
5395     struct wnd_event wnd_event;
5396     BOOL ret;
5397
5398     wnd_event.event = CreateEventW(NULL, 0, 0, NULL);
5399     if (!wnd_event.event)
5400     {
5401         trace("skipping interthread message test under win9x\n");
5402         return;
5403     }
5404
5405     hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
5406     ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
5407
5408     ok(WaitForSingleObject(wnd_event.event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5409
5410     CloseHandle(wnd_event.event);
5411
5412     SetLastError(0xdeadbeef);
5413     ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeded\n");
5414     ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error code %d\n", GetLastError());
5415
5416     proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
5417     ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %d\n", GetLastError());
5418
5419     expected_len = lstrlenA("window caption text");
5420     memset(buf, 0, sizeof(buf));
5421     SetLastError(0xdeadbeef);
5422     len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
5423     ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %d, len %d, expected len %d\n", GetLastError(), len, expected_len);
5424     ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
5425
5426     msg.hwnd = wnd_event.hwnd;
5427     msg.message = WM_GETTEXT;
5428     msg.wParam = sizeof(buf);
5429     msg.lParam = (LPARAM)buf;
5430     memset(buf, 0, sizeof(buf));
5431     SetLastError(0xdeadbeef);
5432     len = DispatchMessageA(&msg);
5433     ok(!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
5434        "DispatchMessageA(WM_GETTEXT) succeded on another thread window: ret %d, error %d\n", len, GetLastError());
5435
5436     /* the following test causes an exception in user.exe under win9x */
5437     msg.hwnd = wnd_event.hwnd;
5438     msg.message = WM_TIMER;
5439     msg.wParam = 0;
5440     msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
5441     SetLastError(0xdeadbeef);
5442     len = DispatchMessageA(&msg);
5443     ok(!len && GetLastError() == 0xdeadbeef,
5444        "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %d\n", len, GetLastError());
5445
5446     ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
5447     ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
5448
5449     ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5450     CloseHandle(hThread);
5451
5452     ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
5453 }
5454
5455
5456 static const struct message WmVkN[] = {
5457     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
5458     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
5459     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
5460     { WM_CHAR, wparam|lparam, 'n', 1 },
5461     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
5462     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
5463     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
5464     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
5465     { 0 }
5466 };
5467 static const struct message WmShiftVkN[] = {
5468     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
5469     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
5470     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
5471     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
5472     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
5473     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
5474     { WM_CHAR, wparam|lparam, 'N', 1 },
5475     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
5476     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
5477     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
5478     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
5479     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
5480     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
5481     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
5482     { 0 }
5483 };
5484 static const struct message WmCtrlVkN[] = {
5485     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
5486     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
5487     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
5488     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
5489     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
5490     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
5491     { WM_CHAR, wparam|lparam, 0x000e, 1 },
5492     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
5493     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
5494     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
5495     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
5496     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
5497     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
5498     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
5499     { 0 }
5500 };
5501 static const struct message WmCtrlVkN_2[] = {
5502     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
5503     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
5504     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
5505     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
5506     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
5507     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
5508     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
5509     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
5510     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
5511     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
5512     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
5513     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
5514     { 0 }
5515 };
5516 static const struct message WmAltVkN[] = {
5517     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
5518     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
5519     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
5520     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
5521     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
5522     { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
5523     { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
5524     { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
5525     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
5526     { HCBT_SYSCOMMAND, hook },
5527     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
5528     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5529     { 0x00AE, sent|defwinproc|optional }, /* XP */
5530     { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
5531     { WM_INITMENU, sent|defwinproc },
5532     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
5533     { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
5534     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
5535     { WM_CAPTURECHANGED, sent|defwinproc },
5536     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
5537     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
5538     { WM_EXITMENULOOP, sent|defwinproc },
5539     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
5540     { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
5541     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
5542     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
5543     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
5544     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
5545     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
5546     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
5547     { 0 }
5548 };
5549 static const struct message WmAltVkN_2[] = {
5550     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
5551     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
5552     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
5553     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
5554     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
5555     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
5556     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
5557     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
5558     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
5559     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
5560     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
5561     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
5562     { 0 }
5563 };
5564 static const struct message WmCtrlAltVkN[] = {
5565     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
5566     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
5567     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
5568     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
5569     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
5570     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
5571     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
5572     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
5573     { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
5574     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
5575     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
5576     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
5577     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
5578     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
5579     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
5580     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
5581     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
5582     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
5583     { 0 }
5584 };
5585 static const struct message WmCtrlShiftVkN[] = {
5586     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
5587     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
5588     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
5589     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
5590     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
5591     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
5592     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
5593     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
5594     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
5595     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
5596     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
5597     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
5598     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
5599     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
5600     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
5601     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
5602     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
5603     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
5604     { 0 }
5605 };
5606 static const struct message WmCtrlAltShiftVkN[] = {
5607     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
5608     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
5609     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
5610     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
5611     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
5612     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
5613     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
5614     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
5615     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
5616     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
5617     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
5618     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
5619     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
5620     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
5621     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
5622     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
5623     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
5624     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
5625     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
5626     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
5627     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
5628     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
5629     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
5630     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
5631     { 0 }
5632 };
5633 static const struct message WmAltPressRelease[] = {
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     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
5638     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
5639     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
5640     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
5641     { HCBT_SYSCOMMAND, hook },
5642     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
5643     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5644     { WM_INITMENU, sent|defwinproc },
5645     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
5646     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
5647     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
5648
5649     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
5650
5651     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
5652     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
5653     { WM_CAPTURECHANGED, sent|defwinproc },
5654     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
5655     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
5656     { WM_EXITMENULOOP, sent|defwinproc },
5657     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
5658     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
5659     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
5660     { 0 }
5661 };
5662 static const struct message WmAltMouseButton[] = {
5663     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
5664     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
5665     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
5666     { WM_MOUSEMOVE, wparam|optional, 0, 0 },
5667     { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
5668     { WM_LBUTTONDOWN, wparam, MK_LBUTTON, 0 },
5669     { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON, 0 },
5670     { WM_LBUTTONUP, wparam, 0, 0 },
5671     { WM_LBUTTONUP, sent|wparam, 0, 0 },
5672     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
5673     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
5674     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
5675     { 0 }
5676 };
5677 static const struct message WmF1Seq[] = {
5678     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
5679     { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
5680     { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
5681     { 0x4d, wparam|lparam, 0, 0 },
5682     { 0x4d, sent|wparam|lparam, 0, 0 },
5683     { WM_HELP, sent|defwinproc },
5684     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
5685     { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
5686     { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
5687     { 0 }
5688 };
5689 static const struct message WmVkAppsSeq[] = {
5690     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
5691     { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
5692     { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
5693     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
5694     { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
5695     { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
5696     { WM_CONTEXTMENU, lparam, /*hwnd*/0, (LPARAM)-1 },
5697     { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, (LPARAM)-1 },
5698     { 0 }
5699 };
5700
5701 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
5702 {
5703     MSG msg;
5704
5705     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
5706     {
5707         struct message log_msg;
5708
5709         trace("accel: %p, %04x, %08lx, %08lx\n", msg.hwnd, msg.message, msg.wParam, msg.lParam);
5710
5711         /* ignore some unwanted messages */
5712         if (msg.message == WM_MOUSEMOVE ||
5713             msg.message == WM_GETICON ||
5714             msg.message == WM_DEVICECHANGE)
5715             continue;
5716
5717         log_msg.message = msg.message;
5718         log_msg.flags = wparam|lparam;
5719         log_msg.wParam = msg.wParam;
5720         log_msg.lParam = msg.lParam;
5721         add_message(&log_msg);
5722
5723         if (!hAccel || !TranslateAccelerator(hwnd, hAccel, &msg))
5724         {
5725             TranslateMessage(&msg);
5726             DispatchMessage(&msg);
5727         }
5728     }
5729 }
5730
5731 static void test_accelerators(void)
5732 {
5733     RECT rc;
5734     SHORT state;
5735     HACCEL hAccel;
5736     HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5737                                 100, 100, 200, 200, 0, 0, 0, NULL);
5738     BOOL ret;
5739
5740     assert(hwnd != 0);
5741     UpdateWindow(hwnd);
5742     flush_events();
5743     flush_sequence();
5744
5745     SetFocus(hwnd);
5746     ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
5747
5748     state = GetKeyState(VK_SHIFT);
5749     ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
5750     state = GetKeyState(VK_CAPITAL);
5751     ok(state == 0, "wrong CapsLock state %04x\n", state);
5752
5753     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(1));
5754     assert(hAccel != 0);
5755
5756     pump_msg_loop(hwnd, 0);
5757     flush_sequence();
5758
5759     trace("testing VK_N press/release\n");
5760     flush_sequence();
5761     keybd_event('N', 0, 0, 0);
5762     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5763     pump_msg_loop(hwnd, hAccel);
5764     ok_sequence(WmVkN, "VK_N press/release", FALSE);
5765
5766     trace("testing Shift+VK_N press/release\n");
5767     flush_sequence();
5768     keybd_event(VK_SHIFT, 0, 0, 0);
5769     keybd_event('N', 0, 0, 0);
5770     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5771     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
5772     pump_msg_loop(hwnd, hAccel);
5773     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
5774
5775     trace("testing Ctrl+VK_N press/release\n");
5776     flush_sequence();
5777     keybd_event(VK_CONTROL, 0, 0, 0);
5778     keybd_event('N', 0, 0, 0);
5779     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5780     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
5781     pump_msg_loop(hwnd, hAccel);
5782     ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
5783
5784     trace("testing Alt+VK_N press/release\n");
5785     flush_sequence();
5786     keybd_event(VK_MENU, 0, 0, 0);
5787     keybd_event('N', 0, 0, 0);
5788     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5789     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
5790     pump_msg_loop(hwnd, hAccel);
5791     ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
5792
5793     trace("testing Ctrl+Alt+VK_N press/release 1\n");
5794     flush_sequence();
5795     keybd_event(VK_CONTROL, 0, 0, 0);
5796     keybd_event(VK_MENU, 0, 0, 0);
5797     keybd_event('N', 0, 0, 0);
5798     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5799     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
5800     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
5801     pump_msg_loop(hwnd, hAccel);
5802     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
5803
5804     ret = DestroyAcceleratorTable(hAccel);
5805     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
5806
5807     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(2));
5808     assert(hAccel != 0);
5809
5810     trace("testing VK_N press/release\n");
5811     flush_sequence();
5812     keybd_event('N', 0, 0, 0);
5813     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5814     pump_msg_loop(hwnd, hAccel);
5815     ok_sequence(WmVkN, "VK_N press/release", FALSE);
5816
5817     trace("testing Shift+VK_N press/release\n");
5818     flush_sequence();
5819     keybd_event(VK_SHIFT, 0, 0, 0);
5820     keybd_event('N', 0, 0, 0);
5821     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5822     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
5823     pump_msg_loop(hwnd, hAccel);
5824     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
5825
5826     trace("testing Ctrl+VK_N press/release 2\n");
5827     flush_sequence();
5828     keybd_event(VK_CONTROL, 0, 0, 0);
5829     keybd_event('N', 0, 0, 0);
5830     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5831     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
5832     pump_msg_loop(hwnd, hAccel);
5833     ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
5834
5835     trace("testing Alt+VK_N press/release 2\n");
5836     flush_sequence();
5837     keybd_event(VK_MENU, 0, 0, 0);
5838     keybd_event('N', 0, 0, 0);
5839     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5840     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
5841     pump_msg_loop(hwnd, hAccel);
5842     ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
5843
5844     trace("testing Ctrl+Alt+VK_N press/release 2\n");
5845     flush_sequence();
5846     keybd_event(VK_CONTROL, 0, 0, 0);
5847     keybd_event(VK_MENU, 0, 0, 0);
5848     keybd_event('N', 0, 0, 0);
5849     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5850     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
5851     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
5852     pump_msg_loop(hwnd, hAccel);
5853     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
5854
5855     trace("testing Ctrl+Shift+VK_N press/release\n");
5856     flush_sequence();
5857     keybd_event(VK_CONTROL, 0, 0, 0);
5858     keybd_event(VK_SHIFT, 0, 0, 0);
5859     keybd_event('N', 0, 0, 0);
5860     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5861     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
5862     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
5863     pump_msg_loop(hwnd, hAccel);
5864     ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
5865
5866     trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
5867     flush_sequence();
5868     keybd_event(VK_CONTROL, 0, 0, 0);
5869     keybd_event(VK_MENU, 0, 0, 0);
5870     keybd_event(VK_SHIFT, 0, 0, 0);
5871     keybd_event('N', 0, 0, 0);
5872     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5873     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
5874     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
5875     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
5876     pump_msg_loop(hwnd, hAccel);
5877     ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
5878
5879     ret = DestroyAcceleratorTable(hAccel);
5880     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
5881
5882     trace("testing Alt press/release\n");
5883     flush_sequence();
5884     keybd_event(VK_MENU, 0, 0, 0);
5885     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
5886     keybd_event(VK_MENU, 0, 0, 0);
5887     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
5888     pump_msg_loop(hwnd, 0);
5889     /* this test doesn't pass in Wine for managed windows */
5890     ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
5891
5892     trace("testing Alt+MouseButton press/release\n");
5893     /* first, move mouse pointer inside of the window client area */
5894     GetClientRect(hwnd, &rc);
5895     MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
5896     rc.left += (rc.right - rc.left)/2;
5897     rc.top += (rc.bottom - rc.top)/2;
5898     SetCursorPos(rc.left, rc.top);
5899
5900     flush_events();
5901     flush_sequence();
5902     keybd_event(VK_MENU, 0, 0, 0);
5903     mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
5904     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
5905     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
5906     pump_msg_loop(hwnd, 0);
5907     ok_sequence(WmAltMouseButton, "Alt+MouseButton press/release", FALSE);
5908
5909     trace("testing VK_F1 press/release\n");
5910     keybd_event(VK_F1, 0, 0, 0);
5911     keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
5912     pump_msg_loop(hwnd, 0);
5913     ok_sequence(WmF1Seq, "F1 press/release", TRUE);
5914
5915     trace("testing VK_APPS press/release\n");
5916     keybd_event(VK_APPS, 0, 0, 0);
5917     keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
5918     pump_msg_loop(hwnd, 0);
5919     ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
5920
5921     DestroyWindow(hwnd);
5922 }
5923
5924 /************* window procedures ********************/
5925
5926 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message, 
5927                              WPARAM wParam, LPARAM lParam)
5928 {
5929     static long defwndproc_counter = 0;
5930     static long beginpaint_counter = 0;
5931     LRESULT ret;
5932     struct message msg;
5933
5934     trace("%p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
5935
5936     /* explicitly ignore WM_GETICON message */
5937     if (message == WM_GETICON) return 0;
5938
5939     switch (message)
5940     {
5941         case WM_ENABLE:
5942         {
5943             LONG style = GetWindowLongA(hwnd, GWL_STYLE);
5944             ok((BOOL)wParam == !(style & WS_DISABLED),
5945                 "wrong WS_DISABLED state: %ld != %d\n", wParam, !(style & WS_DISABLED));
5946             break;
5947         }
5948
5949         case WM_CAPTURECHANGED:
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         case WM_NCDESTROY:
5963         {
5964             HWND capture;
5965
5966             ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
5967             capture = GetCapture();
5968             if (capture)
5969             {
5970                 ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
5971                 trace("current capture %p, releasing...\n", capture);
5972                 ReleaseCapture();
5973             }
5974         }
5975         /* fall through */
5976         case WM_DESTROY:
5977             if (pGetAncestor)
5978                 ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
5979             if (test_DestroyWindow_flag)
5980             {
5981                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
5982                 if (style & WS_CHILD)
5983                     lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
5984                 else if (style & WS_POPUP)
5985                     lParam = WND_POPUP_ID;
5986                 else
5987                     lParam = WND_PARENT_ID;
5988             }
5989             break;
5990
5991         /* test_accelerators() depends on this */
5992         case WM_NCHITTEST:
5993             return HTCLIENT;
5994     
5995         /* ignore */
5996         case WM_MOUSEMOVE:
5997         case WM_SETCURSOR:
5998         case WM_DEVICECHANGE:
5999             return 0;
6000
6001         case WM_WINDOWPOSCHANGING:
6002         case WM_WINDOWPOSCHANGED:
6003         {
6004             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
6005
6006             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
6007             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
6008                   winpos->hwnd, winpos->hwndInsertAfter,
6009                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
6010             dump_winpos_flags(winpos->flags);
6011
6012             /* Log only documented flags, win2k uses 0x1000 and 0x2000
6013              * in the high word for internal purposes
6014              */
6015             wParam = winpos->flags & 0xffff;
6016             /* We are not interested in the flags that don't match under XP and Win9x */
6017             wParam &= ~(SWP_NOZORDER);
6018             break;
6019         }
6020     }
6021
6022     msg.message = message;
6023     msg.flags = sent|wparam|lparam;
6024     if (defwndproc_counter) msg.flags |= defwinproc;
6025     if (beginpaint_counter) msg.flags |= beginpaint;
6026     msg.wParam = wParam;
6027     msg.lParam = lParam;
6028     add_message(&msg);
6029
6030     if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
6031     {
6032         HWND parent = GetParent(hwnd);
6033         RECT rc;
6034         MINMAXINFO *minmax = (MINMAXINFO *)lParam;
6035
6036         GetClientRect(parent, &rc);
6037         trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
6038
6039         trace("ptReserved = (%d,%d)\n"
6040               "ptMaxSize = (%d,%d)\n"
6041               "ptMaxPosition = (%d,%d)\n"
6042               "ptMinTrackSize = (%d,%d)\n"
6043               "ptMaxTrackSize = (%d,%d)\n",
6044               minmax->ptReserved.x, minmax->ptReserved.y,
6045               minmax->ptMaxSize.x, minmax->ptMaxSize.y,
6046               minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
6047               minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
6048               minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
6049
6050         ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n",
6051            minmax->ptMaxSize.x, rc.right);
6052         ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %d != %d\n",
6053            minmax->ptMaxSize.y, rc.bottom);
6054     }
6055
6056     if (message == WM_PAINT)
6057     {
6058         PAINTSTRUCT ps;
6059         beginpaint_counter++;
6060         BeginPaint( hwnd, &ps );
6061         beginpaint_counter--;
6062         EndPaint( hwnd, &ps );
6063         return 0;
6064     }
6065
6066     defwndproc_counter++;
6067     ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam) 
6068                   : DefWindowProcA(hwnd, message, wParam, lParam);
6069     defwndproc_counter--;
6070
6071     return ret;
6072 }
6073
6074 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6075 {
6076     return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
6077 }
6078
6079 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6080 {
6081     return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
6082 }
6083
6084 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6085 {
6086     static long defwndproc_counter = 0;
6087     LRESULT ret;
6088     struct message msg;
6089
6090     trace("popup: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
6091
6092     /* explicitly ignore WM_GETICON message */
6093     if (message == WM_GETICON) return 0;
6094
6095     msg.message = message;
6096     msg.flags = sent|wparam|lparam;
6097     if (defwndproc_counter) msg.flags |= defwinproc;
6098     msg.wParam = wParam;
6099     msg.lParam = lParam;
6100     add_message(&msg);
6101
6102     if (message == WM_CREATE)
6103     {
6104         DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
6105         SetWindowLongA(hwnd, GWL_STYLE, style);
6106     }
6107
6108     defwndproc_counter++;
6109     ret = DefWindowProcA(hwnd, message, wParam, lParam);
6110     defwndproc_counter--;
6111
6112     return ret;
6113 }
6114
6115 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6116 {
6117     static long defwndproc_counter = 0;
6118     static long beginpaint_counter = 0;
6119     LRESULT ret;
6120     struct message msg;
6121
6122     trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
6123
6124     /* explicitly ignore WM_GETICON message */
6125     if (message == WM_GETICON) return 0;
6126
6127     if (log_all_parent_messages ||
6128         message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
6129         message == WM_SETFOCUS || message == WM_KILLFOCUS ||
6130         message == WM_ENABLE || message == WM_ENTERIDLE ||
6131         message == WM_IME_SETCONTEXT)
6132     {
6133         switch (message)
6134         {
6135             /* ignore */
6136             case WM_NCHITTEST:
6137                 return HTCLIENT;
6138             case WM_SETCURSOR:
6139             case WM_MOUSEMOVE:
6140                 return 0;
6141
6142             case WM_ERASEBKGND:
6143             {
6144                 RECT rc;
6145                 INT ret = GetClipBox((HDC)wParam, &rc);
6146
6147                 trace("WM_ERASEBKGND: GetClipBox()=%d, (%d,%d-%d,%d)\n",
6148                        ret, rc.left, rc.top, rc.right, rc.bottom);
6149                 break;
6150             }
6151
6152             case WM_WINDOWPOSCHANGING:
6153             case WM_WINDOWPOSCHANGED:
6154             {
6155                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
6156
6157                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
6158                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
6159                       winpos->hwnd, winpos->hwndInsertAfter,
6160                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
6161                 dump_winpos_flags(winpos->flags);
6162
6163                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
6164                  * in the high word for internal purposes
6165                  */
6166                 wParam = winpos->flags & 0xffff;
6167                 /* We are not interested in the flags that don't match under XP and Win9x */
6168                 wParam &= ~(SWP_NOZORDER);
6169                 break;
6170             }
6171         }
6172
6173         msg.message = message;
6174         msg.flags = sent|parent|wparam|lparam;
6175         if (defwndproc_counter) msg.flags |= defwinproc;
6176         if (beginpaint_counter) msg.flags |= beginpaint;
6177         msg.wParam = wParam;
6178         msg.lParam = lParam;
6179         add_message(&msg);
6180     }
6181
6182     if (message == WM_PAINT)
6183     {
6184         PAINTSTRUCT ps;
6185         beginpaint_counter++;
6186         BeginPaint( hwnd, &ps );
6187         beginpaint_counter--;
6188         EndPaint( hwnd, &ps );
6189         return 0;
6190     }
6191
6192     defwndproc_counter++;
6193     ret = DefWindowProcA(hwnd, message, wParam, lParam);
6194     defwndproc_counter--;
6195
6196     return ret;
6197 }
6198
6199 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6200 {
6201     static long defwndproc_counter = 0;
6202     LRESULT ret;
6203     struct message msg;
6204
6205     trace("dialog: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
6206
6207     /* explicitly ignore WM_GETICON message */
6208     if (message == WM_GETICON) return 0;
6209
6210     if (test_def_id)
6211     {
6212         DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
6213         ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
6214         if (after_end_dialog)
6215             ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
6216         else
6217             ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
6218     }
6219
6220     switch (message)
6221     {
6222         case WM_WINDOWPOSCHANGING:
6223         case WM_WINDOWPOSCHANGED:
6224         {
6225             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
6226
6227             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
6228             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
6229                   winpos->hwnd, winpos->hwndInsertAfter,
6230                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
6231             dump_winpos_flags(winpos->flags);
6232
6233             /* Log only documented flags, win2k uses 0x1000 and 0x2000
6234              * in the high word for internal purposes
6235              */
6236             wParam = winpos->flags & 0xffff;
6237             /* We are not interested in the flags that don't match under XP and Win9x */
6238             wParam &= ~(SWP_NOZORDER);
6239             break;
6240         }
6241     }
6242
6243     msg.message = message;
6244     msg.flags = sent|wparam|lparam;
6245     if (defwndproc_counter) msg.flags |= defwinproc;
6246     msg.wParam = wParam;
6247     msg.lParam = lParam;
6248     add_message(&msg);
6249
6250     defwndproc_counter++;
6251     ret = DefDlgProcA(hwnd, message, wParam, lParam);
6252     defwndproc_counter--;
6253
6254     return ret;
6255 }
6256
6257 static void dump_winpos_flags(UINT flags)
6258 {
6259     if (!winetest_debug) return;
6260
6261     if (flags & SWP_SHOWWINDOW) printf("|SWP_SHOWWINDOW");
6262     if (flags & SWP_HIDEWINDOW) printf("|SWP_HIDEWINDOW");
6263     if (flags & SWP_NOACTIVATE) printf("|SWP_NOACTIVATE");
6264     if (flags & SWP_FRAMECHANGED) printf("|SWP_FRAMECHANGED");
6265     if (flags & SWP_NOCOPYBITS) printf("|SWP_NOCOPYBITS");
6266     if (flags & SWP_NOOWNERZORDER) printf("|SWP_NOOWNERZORDER");
6267     if (flags & SWP_NOSENDCHANGING) printf("|SWP_NOSENDCHANGING");
6268     if (flags & SWP_DEFERERASE) printf("|SWP_DEFERERASE");
6269     if (flags & SWP_ASYNCWINDOWPOS) printf("|SWP_ASYNCWINDOWPOS");
6270     if (flags & SWP_NOZORDER) printf("|SWP_NOZORDER");
6271     if (flags & SWP_NOREDRAW) printf("|SWP_NOREDRAW");
6272     if (flags & SWP_NOSIZE) printf("|SWP_NOSIZE");
6273     if (flags & SWP_NOMOVE) printf("|SWP_NOMOVE");
6274     if (flags & SWP_NOCLIENTSIZE) printf("|SWP_NOCLIENTSIZE");
6275     if (flags & SWP_NOCLIENTMOVE) printf("|SWP_NOCLIENTMOVE");
6276
6277 #define DUMPED_FLAGS \
6278     (SWP_NOSIZE | \
6279     SWP_NOMOVE | \
6280     SWP_NOZORDER | \
6281     SWP_NOREDRAW | \
6282     SWP_NOACTIVATE | \
6283     SWP_FRAMECHANGED | \
6284     SWP_SHOWWINDOW | \
6285     SWP_HIDEWINDOW | \
6286     SWP_NOCOPYBITS | \
6287     SWP_NOOWNERZORDER | \
6288     SWP_NOSENDCHANGING | \
6289     SWP_DEFERERASE | \
6290     SWP_ASYNCWINDOWPOS | \
6291     SWP_NOCLIENTSIZE | \
6292     SWP_NOCLIENTMOVE)
6293
6294     if(flags & ~DUMPED_FLAGS) printf("|0x%04x", flags & ~DUMPED_FLAGS);
6295     printf("\n");
6296 #undef DUMPED_FLAGS
6297 }
6298
6299 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6300 {
6301     static long defwndproc_counter = 0;
6302     LRESULT ret;
6303     struct message msg;
6304
6305     /* log only specific messages we are interested in */
6306     switch (message)
6307     {
6308 #if 0 /* probably log these as well */
6309     case WM_ACTIVATE:
6310     case WM_SETFOCUS:
6311     case WM_KILLFOCUS:
6312 #endif
6313     case WM_SHOWWINDOW:
6314         trace("WM_SHOWWINDOW %ld\n", wParam);
6315         break;
6316     case WM_SIZE:
6317         trace("WM_SIZE %ld\n", wParam);
6318         break;
6319     case WM_MOVE:
6320         trace("WM_MOVE\n");
6321         break;
6322     case WM_GETMINMAXINFO:
6323         trace("WM_GETMINMAXINFO\n");
6324         break;
6325
6326     case WM_WINDOWPOSCHANGING:
6327     case WM_WINDOWPOSCHANGED:
6328     {
6329         WINDOWPOS *winpos = (WINDOWPOS *)lParam;
6330
6331         trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
6332         trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
6333               winpos->hwnd, winpos->hwndInsertAfter,
6334               winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
6335         trace("flags: ");
6336         dump_winpos_flags(winpos->flags);
6337
6338         /* Log only documented flags, win2k uses 0x1000 and 0x2000
6339          * in the high word for internal purposes
6340          */
6341         wParam = winpos->flags & 0xffff;
6342         /* We are not interested in the flags that don't match under XP and Win9x */
6343         wParam &= ~(SWP_NOZORDER);
6344         break;
6345     }
6346
6347     default: /* ignore */
6348         /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
6349         return DefWindowProcA(hwnd, message, wParam, lParam);
6350     }
6351
6352     msg.message = message;
6353     msg.flags = sent|wparam|lparam;
6354     if (defwndproc_counter) msg.flags |= defwinproc;
6355     msg.wParam = wParam;
6356     msg.lParam = lParam;
6357     add_message(&msg);
6358
6359     defwndproc_counter++;
6360     ret = DefWindowProcA(hwnd, message, wParam, lParam);
6361     defwndproc_counter--;
6362
6363     return ret;
6364 }
6365
6366 static BOOL RegisterWindowClasses(void)
6367 {
6368     WNDCLASSA cls;
6369     WNDCLASSW clsW;
6370
6371     cls.style = 0;
6372     cls.lpfnWndProc = MsgCheckProcA;
6373     cls.cbClsExtra = 0;
6374     cls.cbWndExtra = 0;
6375     cls.hInstance = GetModuleHandleA(0);
6376     cls.hIcon = 0;
6377     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
6378     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
6379     cls.lpszMenuName = NULL;
6380     cls.lpszClassName = "TestWindowClass";
6381     if(!RegisterClassA(&cls)) return FALSE;
6382
6383     cls.lpfnWndProc = ShowWindowProcA;
6384     cls.lpszClassName = "ShowWindowClass";
6385     if(!RegisterClassA(&cls)) return FALSE;
6386
6387     cls.lpfnWndProc = PopupMsgCheckProcA;
6388     cls.lpszClassName = "TestPopupClass";
6389     if(!RegisterClassA(&cls)) return FALSE;
6390
6391     cls.lpfnWndProc = ParentMsgCheckProcA;
6392     cls.lpszClassName = "TestParentClass";
6393     if(!RegisterClassA(&cls)) return FALSE;
6394
6395     cls.lpfnWndProc = DefWindowProcA;
6396     cls.lpszClassName = "SimpleWindowClass";
6397     if(!RegisterClassA(&cls)) return FALSE;
6398
6399     cls.style = CS_NOCLOSE;
6400     cls.lpszClassName = "NoCloseWindowClass";
6401     if(!RegisterClassA(&cls)) return FALSE;
6402
6403     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
6404     cls.style = 0;
6405     cls.hInstance = GetModuleHandleA(0);
6406     cls.hbrBackground = 0;
6407     cls.lpfnWndProc = TestDlgProcA;
6408     cls.lpszClassName = "TestDialogClass";
6409     if(!RegisterClassA(&cls)) return FALSE;
6410
6411     clsW.style = 0;
6412     clsW.lpfnWndProc = MsgCheckProcW;
6413     clsW.cbClsExtra = 0;
6414     clsW.cbWndExtra = 0;
6415     clsW.hInstance = GetModuleHandleW(0);
6416     clsW.hIcon = 0;
6417     clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
6418     clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
6419     clsW.lpszMenuName = NULL;
6420     clsW.lpszClassName = testWindowClassW;
6421     RegisterClassW(&clsW);  /* ignore error, this fails on Win9x */
6422
6423     return TRUE;
6424 }
6425
6426 static HHOOK hCBT_hook;
6427 static DWORD cbt_hook_thread_id;
6428
6429 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
6430
6431     static const char * const CBT_code_name[10] = {
6432         "HCBT_MOVESIZE",
6433         "HCBT_MINMAX",
6434         "HCBT_QS",
6435         "HCBT_CREATEWND",
6436         "HCBT_DESTROYWND",
6437         "HCBT_ACTIVATE",
6438         "HCBT_CLICKSKIPPED",
6439         "HCBT_KEYSKIPPED",
6440         "HCBT_SYSCOMMAND",
6441         "HCBT_SETFOCUS" };
6442     const char *code_name = (nCode >= 0 && nCode <= HCBT_SETFOCUS) ? CBT_code_name[nCode] : "Unknown";
6443     HWND hwnd;
6444     char buf[256];
6445
6446     trace("CBT: %d (%s), %08lx, %08lx\n", nCode, code_name, wParam, lParam);
6447
6448     ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
6449
6450     if (nCode == HCBT_CLICKSKIPPED)
6451     {
6452         /* ignore this event, XP sends it a lot when switching focus between windows */
6453         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
6454     }
6455
6456     if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
6457     {
6458         struct message msg;
6459
6460         msg.message = nCode;
6461         msg.flags = hook|wparam|lparam;
6462         msg.wParam = wParam;
6463         msg.lParam = lParam;
6464         add_message(&msg);
6465
6466         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
6467     }
6468
6469     if (nCode == HCBT_DESTROYWND)
6470     {
6471         if (test_DestroyWindow_flag)
6472         {
6473             DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
6474             if (style & WS_CHILD)
6475                 lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
6476             else if (style & WS_POPUP)
6477                 lParam = WND_POPUP_ID;
6478             else
6479                 lParam = WND_PARENT_ID;
6480         }
6481     }
6482
6483     /* Log also SetFocus(0) calls */
6484     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
6485
6486     if (GetClassNameA(hwnd, buf, sizeof(buf)))
6487     {
6488         if (!lstrcmpiA(buf, "TestWindowClass") ||
6489             !lstrcmpiA(buf, "ShowWindowClass") ||
6490             !lstrcmpiA(buf, "TestParentClass") ||
6491             !lstrcmpiA(buf, "TestPopupClass") ||
6492             !lstrcmpiA(buf, "SimpleWindowClass") ||
6493             !lstrcmpiA(buf, "TestDialogClass") ||
6494             !lstrcmpiA(buf, "MDI_frame_class") ||
6495             !lstrcmpiA(buf, "MDI_client_class") ||
6496             !lstrcmpiA(buf, "MDI_child_class") ||
6497             !lstrcmpiA(buf, "my_button_class") ||
6498             !lstrcmpiA(buf, "my_edit_class") ||
6499             !lstrcmpiA(buf, "static") ||
6500             !lstrcmpiA(buf, "MyDialogClass") ||
6501             !lstrcmpiA(buf, "#32770"))
6502         {
6503             struct message msg;
6504
6505             msg.message = nCode;
6506             msg.flags = hook|wparam|lparam;
6507             msg.wParam = wParam;
6508             msg.lParam = lParam;
6509             add_message(&msg);
6510         }
6511     }
6512     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
6513 }
6514
6515 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
6516                                     DWORD event,
6517                                     HWND hwnd,
6518                                     LONG object_id,
6519                                     LONG child_id,
6520                                     DWORD thread_id,
6521                                     DWORD event_time)
6522 {
6523     char buf[256];
6524
6525     trace("WEH:%p,event %08x,hwnd %p,obj %08x,id %08x,thread %08x,time %08x\n",
6526            hevent, event, hwnd, object_id, child_id, thread_id, event_time);
6527
6528     ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
6529
6530     /* ignore mouse cursor events */
6531     if (object_id == OBJID_CURSOR) return;
6532
6533     if (!hwnd || GetClassNameA(hwnd, buf, sizeof(buf)))
6534     {
6535         if (!hwnd ||
6536             !lstrcmpiA(buf, "TestWindowClass") ||
6537             !lstrcmpiA(buf, "TestParentClass") ||
6538             !lstrcmpiA(buf, "TestPopupClass") ||
6539             !lstrcmpiA(buf, "SimpleWindowClass") ||
6540             !lstrcmpiA(buf, "TestDialogClass") ||
6541             !lstrcmpiA(buf, "MDI_frame_class") ||
6542             !lstrcmpiA(buf, "MDI_client_class") ||
6543             !lstrcmpiA(buf, "MDI_child_class") ||
6544             !lstrcmpiA(buf, "my_button_class") ||
6545             !lstrcmpiA(buf, "my_edit_class") ||
6546             !lstrcmpiA(buf, "static") ||
6547             !lstrcmpiA(buf, "MyDialogClass") ||
6548             !lstrcmpiA(buf, "#32770"))
6549         {
6550             struct message msg;
6551
6552             msg.message = event;
6553             msg.flags = winevent_hook|wparam|lparam;
6554             msg.wParam = object_id;
6555             msg.lParam = child_id;
6556             add_message(&msg);
6557         }
6558     }
6559 }
6560
6561 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
6562 static const WCHAR wszAnsi[] = {'U',0};
6563
6564 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
6565 {
6566     switch (uMsg)
6567     {
6568     case CB_FINDSTRINGEXACT:
6569         trace("String: %p\n", (LPCWSTR)lParam);
6570         if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
6571             return 1;
6572         if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
6573             return 0;
6574         return -1;
6575     }
6576     return DefWindowProcW(hwnd, uMsg, wParam, lParam);
6577 }
6578
6579 static const struct message WmGetTextLengthAfromW[] = {
6580     { WM_GETTEXTLENGTH, sent },
6581     { WM_GETTEXT, sent },
6582     { 0 }
6583 };
6584
6585 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
6586
6587 /* dummy window proc for WM_GETTEXTLENGTH test */
6588 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
6589 {
6590     switch(msg)
6591     {
6592     case WM_GETTEXTLENGTH:
6593         return lstrlenW(dummy_window_text) + 37;  /* some random length */
6594     case WM_GETTEXT:
6595         lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
6596         return lstrlenW( (LPWSTR)lp );
6597     default:
6598         return DefWindowProcW( hwnd, msg, wp, lp );
6599     }
6600 }
6601
6602 static void test_message_conversion(void)
6603 {
6604     static const WCHAR wszMsgConversionClass[] =
6605         {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
6606     WNDCLASSW cls;
6607     LRESULT lRes;
6608     HWND hwnd;
6609     WNDPROC wndproc, newproc;
6610     BOOL ret;
6611
6612     cls.style = 0;
6613     cls.lpfnWndProc = MsgConversionProcW;
6614     cls.cbClsExtra = 0;
6615     cls.cbWndExtra = 0;
6616     cls.hInstance = GetModuleHandleW(NULL);
6617     cls.hIcon = NULL;
6618     cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
6619     cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
6620     cls.lpszMenuName = NULL;
6621     cls.lpszClassName = wszMsgConversionClass;
6622     /* this call will fail on Win9x, but that doesn't matter as this test is
6623      * meaningless on those platforms */
6624     if(!RegisterClassW(&cls)) return;
6625
6626     hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
6627                            100, 100, 200, 200, 0, 0, 0, NULL);
6628     ok(hwnd != NULL, "Window creation failed\n");
6629
6630     /* {W, A} -> A */
6631
6632     wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
6633     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6634     ok(lRes == 0, "String should have been converted\n");
6635     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6636     ok(lRes == 1, "String shouldn't have been converted\n");
6637
6638     /* {W, A} -> W */
6639
6640     wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
6641     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6642     ok(lRes == 1, "String shouldn't have been converted\n");
6643     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6644     ok(lRes == 1, "String shouldn't have been converted\n");
6645
6646     /* Synchronous messages */
6647
6648     lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6649     ok(lRes == 0, "String should have been converted\n");
6650     lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6651     ok(lRes == 1, "String shouldn't have been converted\n");
6652
6653     /* Asynchronous messages */
6654
6655     SetLastError(0);
6656     lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6657     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6658         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6659     SetLastError(0);
6660     lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6661     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6662         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6663     SetLastError(0);
6664     lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6665     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6666         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6667     SetLastError(0);
6668     lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6669     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6670         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6671     SetLastError(0);
6672     lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6673     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6674         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6675     SetLastError(0);
6676     lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6677     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6678         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6679     SetLastError(0);
6680     lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
6681     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6682         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6683     SetLastError(0);
6684     lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
6685     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6686         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6687
6688     /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
6689
6690     hwnd = CreateWindowW (testWindowClassW, wszUnicode,
6691                           WS_OVERLAPPEDWINDOW,
6692                           100, 100, 200, 200, 0, 0, 0, NULL);
6693     assert(hwnd);
6694     flush_sequence();
6695     lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
6696     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
6697     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
6698         "got bad length %ld\n", lRes );
6699
6700     flush_sequence();
6701     lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
6702                             hwnd, WM_GETTEXTLENGTH, 0, 0);
6703     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
6704     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
6705         "got bad length %ld\n", lRes );
6706
6707     wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
6708     newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
6709     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
6710     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
6711                                      NULL, 0, NULL, NULL ),
6712         "got bad length %ld\n", lRes );
6713
6714     SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc );  /* restore old wnd proc */
6715     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
6716     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
6717                                      NULL, 0, NULL, NULL ),
6718         "got bad length %ld\n", lRes );
6719
6720     ret = DestroyWindow(hwnd);
6721     ok( ret, "DestroyWindow() error %d\n", GetLastError());
6722 }
6723
6724 struct timer_info
6725 {
6726     HWND hWnd;
6727     HANDLE handles[2];
6728     DWORD id;
6729 };
6730
6731 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
6732 {
6733 }
6734
6735 #define TIMER_ID  0x19
6736
6737 static DWORD WINAPI timer_thread_proc(LPVOID x)
6738 {
6739     struct timer_info *info = x;
6740     DWORD r;
6741
6742     r = KillTimer(info->hWnd, 0x19);
6743     ok(r,"KillTimer failed in thread\n");
6744     r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
6745     ok(r,"SetTimer failed in thread\n");
6746     ok(r==TIMER_ID,"SetTimer id different\n");
6747     r = SetEvent(info->handles[0]);
6748     ok(r,"SetEvent failed in thread\n");
6749     return 0;
6750 }
6751
6752 static void test_timers(void)
6753 {
6754     struct timer_info info;
6755     DWORD id;
6756
6757     info.hWnd = CreateWindow ("TestWindowClass", NULL,
6758        WS_OVERLAPPEDWINDOW ,
6759        CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
6760        NULL, NULL, 0);
6761
6762     info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
6763     ok(info.id, "SetTimer failed\n");
6764     ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
6765     info.handles[0] = CreateEvent(NULL,0,0,NULL);
6766     info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
6767
6768     WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
6769
6770     WaitForSingleObject(info.handles[1], INFINITE);
6771
6772     CloseHandle(info.handles[0]);
6773     CloseHandle(info.handles[1]);
6774
6775     ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
6776
6777     ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
6778 }
6779
6780 /* Various win events with arbitrary parameters */
6781 static const struct message WmWinEventsSeq[] = {
6782     { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
6783     { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
6784     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
6785     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
6786     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
6787     { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
6788     { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
6789     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
6790     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
6791     /* our win event hook ignores OBJID_CURSOR events */
6792     /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
6793     { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
6794     { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
6795     { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
6796     { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
6797     { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
6798     { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
6799     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
6800     { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
6801     { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
6802     { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
6803     { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
6804     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
6805     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
6806     { 0 }
6807 };
6808 static const struct message WmWinEventCaretSeq[] = {
6809     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
6810     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
6811     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
6812     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
6813     { 0 }
6814 };
6815 static const struct message WmWinEventCaretSeq_2[] = {
6816     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
6817     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
6818     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
6819     { 0 }
6820 };
6821 static const struct message WmWinEventAlertSeq[] = {
6822     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
6823     { 0 }
6824 };
6825 static const struct message WmWinEventAlertSeq_2[] = {
6826     /* create window in the thread proc */
6827     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
6828     /* our test event */
6829     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
6830     { 0 }
6831 };
6832 static const struct message WmGlobalHookSeq_1[] = {
6833     /* create window in the thread proc */
6834     { HCBT_CREATEWND, hook|lparam, 0, 2 },
6835     /* our test events */
6836     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
6837     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
6838     { 0 }
6839 };
6840 static const struct message WmGlobalHookSeq_2[] = {
6841     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
6842     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
6843     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
6844     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
6845     { 0 }
6846 };
6847
6848 static const struct message WmMouseLLHookSeq[] = {
6849     { WM_MOUSEMOVE, hook },
6850     { WM_LBUTTONUP, hook },
6851     { WM_MOUSEMOVE, hook },
6852     { 0 }
6853 };
6854
6855 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
6856                                          DWORD event,
6857                                          HWND hwnd,
6858                                          LONG object_id,
6859                                          LONG child_id,
6860                                          DWORD thread_id,
6861                                          DWORD event_time)
6862 {
6863     char buf[256];
6864
6865     trace("WEH_2:%p,event %08x,hwnd %p,obj %08x,id %08x,thread %08x,time %08x\n",
6866            hevent, event, hwnd, object_id, child_id, thread_id, event_time);
6867
6868     if (GetClassNameA(hwnd, buf, sizeof(buf)))
6869     {
6870         if (!lstrcmpiA(buf, "TestWindowClass") ||
6871             !lstrcmpiA(buf, "static"))
6872         {
6873             struct message msg;
6874
6875             msg.message = event;
6876             msg.flags = winevent_hook|wparam|lparam;
6877             msg.wParam = object_id;
6878             msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
6879             add_message(&msg);
6880         }
6881     }
6882 }
6883
6884 static HHOOK hCBT_global_hook;
6885 static DWORD cbt_global_hook_thread_id;
6886
6887 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
6888
6889     HWND hwnd;
6890     char buf[256];
6891
6892     trace("CBT_2: %d, %08lx, %08lx\n", nCode, wParam, lParam);
6893
6894     if (nCode == HCBT_SYSCOMMAND)
6895     {
6896         struct message msg;
6897
6898         msg.message = nCode;
6899         msg.flags = hook|wparam|lparam;
6900         msg.wParam = wParam;
6901         msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
6902         add_message(&msg);
6903
6904         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
6905     }
6906     /* WH_MOUSE_LL hook */
6907     if (nCode == HC_ACTION)
6908     {
6909         struct message msg;
6910         MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
6911
6912         /* we can't test for real mouse events */
6913         if (mhll->flags & LLMHF_INJECTED)
6914         {
6915             msg.message = wParam;
6916             msg.flags = hook;
6917             add_message(&msg);
6918         }
6919         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
6920     }
6921
6922     /* Log also SetFocus(0) calls */
6923     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
6924
6925     if (GetClassNameA(hwnd, buf, sizeof(buf)))
6926     {
6927         if (!lstrcmpiA(buf, "TestWindowClass") ||
6928             !lstrcmpiA(buf, "static"))
6929         {
6930             struct message msg;
6931
6932             msg.message = nCode;
6933             msg.flags = hook|wparam|lparam;
6934             msg.wParam = wParam;
6935             msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
6936             add_message(&msg);
6937         }
6938     }
6939     return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
6940 }
6941
6942 static DWORD WINAPI win_event_global_thread_proc(void *param)
6943 {
6944     HWND hwnd;
6945     MSG msg;
6946     HANDLE hevent = *(HANDLE *)param;
6947
6948     assert(pNotifyWinEvent);
6949
6950     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
6951     assert(hwnd);
6952     trace("created thread window %p\n", hwnd);
6953
6954     *(HWND *)param = hwnd;
6955
6956     flush_sequence();
6957     /* this event should be received only by our new hook proc,
6958      * an old one does not expect an event from another thread.
6959      */
6960     pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
6961     SetEvent(hevent);
6962
6963     while (GetMessage(&msg, 0, 0, 0))
6964     {
6965         TranslateMessage(&msg);
6966         DispatchMessage(&msg);
6967     }
6968     return 0;
6969 }
6970
6971 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
6972 {
6973     HWND hwnd;
6974     MSG msg;
6975     HANDLE hevent = *(HANDLE *)param;
6976
6977     flush_sequence();
6978     /* these events should be received only by our new hook proc,
6979      * an old one does not expect an event from another thread.
6980      */
6981
6982     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
6983     assert(hwnd);
6984     trace("created thread window %p\n", hwnd);
6985
6986     *(HWND *)param = hwnd;
6987
6988     /* Windows doesn't like when a thread plays games with the focus,
6989        that leads to all kinds of misbehaviours and failures to activate
6990        a window. So, better keep next lines commented out.
6991     SetFocus(0);
6992     SetFocus(hwnd);*/
6993
6994     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
6995     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
6996
6997     SetEvent(hevent);
6998
6999     while (GetMessage(&msg, 0, 0, 0))
7000     {
7001         TranslateMessage(&msg);
7002         DispatchMessage(&msg);
7003     }
7004     return 0;
7005 }
7006
7007 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
7008 {
7009     HWND hwnd;
7010     MSG msg;
7011     HANDLE hevent = *(HANDLE *)param;
7012
7013     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
7014     assert(hwnd);
7015     trace("created thread window %p\n", hwnd);
7016
7017     *(HWND *)param = hwnd;
7018
7019     flush_sequence();
7020
7021     /* Windows doesn't like when a thread plays games with the focus,
7022      * that leads to all kinds of misbehaviours and failures to activate
7023      * a window. So, better don't generate a mouse click message below.
7024      */
7025     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
7026     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
7027     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
7028
7029     SetEvent(hevent);
7030     while (GetMessage(&msg, 0, 0, 0))
7031     {
7032         TranslateMessage(&msg);
7033         DispatchMessage(&msg);
7034     }
7035     return 0;
7036 }
7037
7038 static void test_winevents(void)
7039 {
7040     BOOL ret;
7041     MSG msg;
7042     HWND hwnd, hwnd2;
7043     UINT i;
7044     HANDLE hthread, hevent;
7045     DWORD tid;
7046     HWINEVENTHOOK hhook;
7047     const struct message *events = WmWinEventsSeq;
7048
7049     hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
7050                            WS_OVERLAPPEDWINDOW,
7051                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
7052                            NULL, NULL, 0);
7053     assert(hwnd);
7054
7055     /****** start of global hook test *************/
7056     hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
7057     assert(hCBT_global_hook);
7058
7059     hevent = CreateEventA(NULL, 0, 0, NULL);
7060     assert(hevent);
7061     hwnd2 = (HWND)hevent;
7062
7063     hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
7064     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7065
7066     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7067
7068     ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
7069
7070     flush_sequence();
7071     /* this one should be received only by old hook proc */
7072     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
7073     /* this one should be received only by old hook proc */
7074     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
7075
7076     ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
7077
7078     ret = UnhookWindowsHookEx(hCBT_global_hook);
7079     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
7080
7081     PostThreadMessageA(tid, WM_QUIT, 0, 0);
7082     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7083     CloseHandle(hthread);
7084     CloseHandle(hevent);
7085     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7086     /****** end of global hook test *************/
7087
7088     if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
7089     {
7090         ok(DestroyWindow(hwnd), "failed to destroy window\n");
7091         return;
7092     }
7093
7094     flush_sequence();
7095
7096     if (0)
7097     {
7098     /* this test doesn't pass under Win9x */
7099     /* win2k ignores events with hwnd == 0 */
7100     SetLastError(0xdeadbeef);
7101     pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
7102     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
7103        GetLastError() == 0xdeadbeef, /* Win9x */
7104        "unexpected error %d\n", GetLastError());
7105     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
7106     }
7107
7108     for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++)
7109         pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
7110
7111     ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
7112
7113     /****** start of event filtering test *************/
7114     hhook = (HWINEVENTHOOK)pSetWinEventHook(
7115         EVENT_OBJECT_SHOW, /* 0x8002 */
7116         EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
7117         GetModuleHandleA(0), win_event_global_hook_proc,
7118         GetCurrentProcessId(), 0,
7119         WINEVENT_INCONTEXT);
7120     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
7121
7122     hevent = CreateEventA(NULL, 0, 0, NULL);
7123     assert(hevent);
7124     hwnd2 = (HWND)hevent;
7125
7126     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
7127     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7128
7129     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7130
7131     ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
7132
7133     flush_sequence();
7134     /* this one should be received only by old hook proc */
7135     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
7136     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
7137     /* this one should be received only by old hook proc */
7138     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
7139
7140     ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
7141
7142     ret = pUnhookWinEvent(hhook);
7143     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
7144
7145     PostThreadMessageA(tid, WM_QUIT, 0, 0);
7146     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7147     CloseHandle(hthread);
7148     CloseHandle(hevent);
7149     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7150     /****** end of event filtering test *************/
7151
7152     /****** start of out of context event test *************/
7153     hhook = (HWINEVENTHOOK)pSetWinEventHook(
7154         EVENT_MIN, EVENT_MAX,
7155         0, win_event_global_hook_proc,
7156         GetCurrentProcessId(), 0,
7157         WINEVENT_OUTOFCONTEXT);
7158     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
7159
7160     hevent = CreateEventA(NULL, 0, 0, NULL);
7161     assert(hevent);
7162     hwnd2 = (HWND)hevent;
7163
7164     flush_sequence();
7165
7166     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
7167     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7168
7169     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7170
7171     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
7172     /* process pending winevent messages */
7173     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
7174     ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
7175
7176     flush_sequence();
7177     /* this one should be received only by old hook proc */
7178     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
7179     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
7180     /* this one should be received only by old hook proc */
7181     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
7182
7183     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
7184     /* process pending winevent messages */
7185     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
7186     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
7187
7188     ret = pUnhookWinEvent(hhook);
7189     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
7190
7191     PostThreadMessageA(tid, WM_QUIT, 0, 0);
7192     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7193     CloseHandle(hthread);
7194     CloseHandle(hevent);
7195     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7196     /****** end of out of context event test *************/
7197
7198     /****** start of MOUSE_LL hook test *************/
7199     hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
7200     /* WH_MOUSE_LL is not supported on Win9x platforms */
7201     if (!hCBT_global_hook)
7202     {
7203         trace("Skipping WH_MOUSE_LL test on this platform\n");
7204         goto skip_mouse_ll_hook_test;
7205     }
7206
7207     hevent = CreateEventA(NULL, 0, 0, NULL);
7208     assert(hevent);
7209     hwnd2 = (HWND)hevent;
7210
7211     hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
7212     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7213
7214     while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
7215         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
7216
7217     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
7218     flush_sequence();
7219
7220     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
7221     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
7222     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
7223
7224     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
7225
7226     ret = UnhookWindowsHookEx(hCBT_global_hook);
7227     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
7228
7229     PostThreadMessageA(tid, WM_QUIT, 0, 0);
7230     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7231     CloseHandle(hthread);
7232     CloseHandle(hevent);
7233     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7234     /****** end of MOUSE_LL hook test *************/
7235 skip_mouse_ll_hook_test:
7236
7237     ok(DestroyWindow(hwnd), "failed to destroy window\n");
7238 }
7239
7240 static void test_set_hook(void)
7241 {
7242     BOOL ret;
7243     HHOOK hhook;
7244     HWINEVENTHOOK hwinevent_hook;
7245
7246     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
7247     ok(hhook != 0, "local hook does not require hModule set to 0\n");
7248     UnhookWindowsHookEx(hhook);
7249
7250     if (0)
7251     {
7252     /* this test doesn't pass under Win9x: BUG! */
7253     SetLastError(0xdeadbeef);
7254     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
7255     ok(!hhook, "global hook requires hModule != 0\n");
7256     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
7257     }
7258
7259     SetLastError(0xdeadbeef);
7260     hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
7261     ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
7262     ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
7263        GetLastError() == 0xdeadbeef, /* Win9x */
7264        "unexpected error %d\n", GetLastError());
7265
7266     SetLastError(0xdeadbeef);
7267     ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
7268     ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
7269        GetLastError() == 0xdeadbeef, /* Win9x */
7270        "unexpected error %d\n", GetLastError());
7271
7272     if (!pSetWinEventHook || !pUnhookWinEvent) return;
7273
7274     /* even process local incontext hooks require hmodule */
7275     SetLastError(0xdeadbeef);
7276     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
7277         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
7278     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
7279     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
7280        GetLastError() == 0xdeadbeef, /* Win9x */
7281        "unexpected error %d\n", GetLastError());
7282
7283     /* even thread local incontext hooks require hmodule */
7284     SetLastError(0xdeadbeef);
7285     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
7286         0, win_event_proc, GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
7287     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
7288     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
7289        GetLastError() == 0xdeadbeef, /* Win9x */
7290        "unexpected error %d\n", GetLastError());
7291
7292     if (0)
7293     {
7294     /* these 3 tests don't pass under Win9x */
7295     SetLastError(0xdeadbeef);
7296     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(1, 0,
7297         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
7298     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
7299     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
7300
7301     SetLastError(0xdeadbeef);
7302     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(-1, 1,
7303         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
7304     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
7305     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
7306
7307     SetLastError(0xdeadbeef);
7308     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
7309         0, win_event_proc, 0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
7310     ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
7311     ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
7312     }
7313
7314     SetLastError(0xdeadbeef);
7315     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(0, 0,
7316         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
7317     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
7318     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
7319     ret = pUnhookWinEvent(hwinevent_hook);
7320     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
7321
7322 todo_wine {
7323     /* This call succeeds under win2k SP4, but fails under Wine.
7324        Does win2k test/use passed process id? */
7325     SetLastError(0xdeadbeef);
7326     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
7327         0, win_event_proc, 0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
7328     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
7329     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
7330     ret = pUnhookWinEvent(hwinevent_hook);
7331     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
7332 }
7333
7334     SetLastError(0xdeadbeef);
7335     ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
7336     ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
7337         GetLastError() == 0xdeadbeef, /* Win9x */
7338         "unexpected error %d\n", GetLastError());
7339 }
7340
7341 static const struct message ScrollWindowPaint1[] = {
7342     { WM_PAINT, sent },
7343     { WM_ERASEBKGND, sent|beginpaint },
7344     { 0 }
7345 };
7346
7347 static const struct message ScrollWindowPaint2[] = {
7348     { WM_PAINT, sent },
7349     { 0 }
7350 };
7351
7352 static void test_scrollwindowex(void)
7353 {
7354     HWND hwnd, hchild;
7355     RECT rect={0,0,130,130};
7356
7357     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
7358             WS_VISIBLE|WS_OVERLAPPEDWINDOW,
7359             100, 100, 200, 200, 0, 0, 0, NULL);
7360     ok (hwnd != 0, "Failed to create overlapped window\n");
7361     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", 
7362             WS_VISIBLE|WS_CAPTION|WS_CHILD,
7363             10, 10, 150, 150, hwnd, 0, 0, NULL);
7364     ok (hchild != 0, "Failed to create child\n");
7365     UpdateWindow(hwnd);
7366     flush_events();
7367     flush_sequence();
7368
7369     /* scroll without the child window */
7370     trace("start scroll\n");
7371     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
7372             SW_ERASE|SW_INVALIDATE);
7373     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
7374     trace("end scroll\n");
7375     flush_sequence();
7376     flush_events();
7377     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
7378     flush_events();
7379     flush_sequence();
7380
7381     /* Now without the SW_ERASE flag */
7382     trace("start scroll\n");
7383     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
7384     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
7385     trace("end scroll\n");
7386     flush_sequence();
7387     flush_events();
7388     ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", 0);
7389     flush_events();
7390     flush_sequence();
7391
7392     /* now scroll the child window as well */
7393     trace("start scroll\n");
7394     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
7395             SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
7396     todo_wine { /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
7397                 /* windows sometimes a WM_MOVE */
7398         ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
7399     }
7400     trace("end scroll\n");
7401     flush_sequence();
7402     flush_events();
7403     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
7404     flush_events();
7405     flush_sequence();
7406
7407     /* now scroll with ScrollWindow() */
7408     trace("start scroll with ScrollWindow\n");
7409     ScrollWindow( hwnd, 5, 5, NULL, NULL);
7410     trace("end scroll\n");
7411     flush_sequence();
7412     flush_events();
7413     ok_sequence(ScrollWindowPaint1, "ScrollWindow", 0);
7414
7415     ok(DestroyWindow(hchild), "failed to destroy window\n");
7416     ok(DestroyWindow(hwnd), "failed to destroy window\n");
7417     flush_sequence();
7418 }
7419
7420 static const struct message destroy_window_with_children[] = {
7421     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
7422     { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
7423     { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
7424     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
7425     { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
7426     { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
7427     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
7428     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
7429     { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
7430     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
7431     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
7432     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
7433     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
7434     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
7435     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
7436     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
7437     { 0 }
7438 };
7439
7440 static void test_DestroyWindow(void)
7441 {
7442     BOOL ret;
7443     HWND parent, child1, child2, child3, child4, test;
7444     UINT child_id = WND_CHILD_ID + 1;
7445
7446     parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
7447                              100, 100, 200, 200, 0, 0, 0, NULL);
7448     assert(parent != 0);
7449     child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
7450                              0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
7451     assert(child1 != 0);
7452     child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
7453                              0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
7454     assert(child2 != 0);
7455     child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
7456                              0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
7457     assert(child3 != 0);
7458     child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
7459                              0, 0, 50, 50, parent, 0, 0, NULL);
7460     assert(child4 != 0);
7461
7462     /* test owner/parent of child2 */
7463     test = GetParent(child2);
7464     ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
7465     ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
7466     if(pGetAncestor) {
7467         test = pGetAncestor(child2, GA_PARENT);
7468         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
7469     }
7470     test = GetWindow(child2, GW_OWNER);
7471     ok(!test, "wrong owner %p\n", test);
7472
7473     test = SetParent(child2, parent);
7474     ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
7475
7476     /* test owner/parent of the parent */
7477     test = GetParent(parent);
7478     ok(!test, "wrong parent %p\n", test);
7479 todo_wine {
7480     ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
7481 }
7482     if(pGetAncestor) {
7483         test = pGetAncestor(parent, GA_PARENT);
7484         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
7485     }
7486     test = GetWindow(parent, GW_OWNER);
7487     ok(!test, "wrong owner %p\n", test);
7488
7489     /* test owner/parent of child1 */
7490     test = GetParent(child1);
7491     ok(test == parent, "wrong parent %p\n", test);
7492     ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
7493     if(pGetAncestor) {
7494         test = pGetAncestor(child1, GA_PARENT);
7495         ok(test == parent, "wrong parent %p\n", test);
7496     }
7497     test = GetWindow(child1, GW_OWNER);
7498     ok(!test, "wrong owner %p\n", test);
7499
7500     /* test owner/parent of child2 */
7501     test = GetParent(child2);
7502     ok(test == parent, "wrong parent %p\n", test);
7503     ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
7504     if(pGetAncestor) {
7505         test = pGetAncestor(child2, GA_PARENT);
7506         ok(test == parent, "wrong parent %p\n", test);
7507     }
7508     test = GetWindow(child2, GW_OWNER);
7509     ok(!test, "wrong owner %p\n", test);
7510
7511     /* test owner/parent of child3 */
7512     test = GetParent(child3);
7513     ok(test == child1, "wrong parent %p\n", test);
7514     ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
7515     if(pGetAncestor) {
7516         test = pGetAncestor(child3, GA_PARENT);
7517         ok(test == child1, "wrong parent %p\n", test);
7518     }
7519     test = GetWindow(child3, GW_OWNER);
7520     ok(!test, "wrong owner %p\n", test);
7521
7522     /* test owner/parent of child4 */
7523     test = GetParent(child4);
7524     ok(test == parent, "wrong parent %p\n", test);
7525     ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
7526     if(pGetAncestor) {
7527         test = pGetAncestor(child4, GA_PARENT);
7528         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
7529     }
7530     test = GetWindow(child4, GW_OWNER);
7531     ok(test == parent, "wrong owner %p\n", test);
7532
7533     flush_sequence();
7534
7535     trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
7536            parent, child1, child2, child3, child4);
7537
7538     SetCapture(child4);
7539     test = GetCapture();
7540     ok(test == child4, "wrong capture window %p\n", test);
7541
7542     test_DestroyWindow_flag = TRUE;
7543     ret = DestroyWindow(parent);
7544     ok( ret, "DestroyWindow() error %d\n", GetLastError());
7545     test_DestroyWindow_flag = FALSE;
7546     ok_sequence(destroy_window_with_children, "destroy window with children", 0);
7547
7548     ok(!IsWindow(parent), "parent still exists\n");
7549     ok(!IsWindow(child1), "child1 still exists\n");
7550     ok(!IsWindow(child2), "child2 still exists\n");
7551     ok(!IsWindow(child3), "child3 still exists\n");
7552     ok(!IsWindow(child4), "child4 still exists\n");
7553
7554     test = GetCapture();
7555     ok(!test, "wrong capture window %p\n", test);
7556 }
7557
7558
7559 static const struct message WmDispatchPaint[] = {
7560     { WM_NCPAINT, sent },
7561     { WM_GETTEXT, sent|defwinproc|optional },
7562     { WM_GETTEXT, sent|defwinproc|optional },
7563     { WM_ERASEBKGND, sent },
7564     { 0 }
7565 };
7566
7567 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7568 {
7569     if (message == WM_PAINT) return 0;
7570     return MsgCheckProcA( hwnd, message, wParam, lParam );
7571 }
7572
7573 static void test_DispatchMessage(void)
7574 {
7575     RECT rect;
7576     MSG msg;
7577     int count;
7578     HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
7579                                100, 100, 200, 200, 0, 0, 0, NULL);
7580     ShowWindow( hwnd, SW_SHOW );
7581     UpdateWindow( hwnd );
7582     flush_events();
7583     flush_sequence();
7584     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
7585
7586     SetRect( &rect, -5, -5, 5, 5 );
7587     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
7588     count = 0;
7589     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
7590     {
7591         if (msg.message != WM_PAINT) DispatchMessage( &msg );
7592         else
7593         {
7594             flush_sequence();
7595             DispatchMessage( &msg );
7596             /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
7597             if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
7598             else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
7599             if (++count > 10) break;
7600         }
7601     }
7602     ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
7603
7604     trace("now without DispatchMessage\n");
7605     flush_sequence();
7606     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
7607     count = 0;
7608     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
7609     {
7610         if (msg.message != WM_PAINT) DispatchMessage( &msg );
7611         else
7612         {
7613             HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
7614             flush_sequence();
7615             /* this will send WM_NCCPAINT just like DispatchMessage does */
7616             GetUpdateRgn( hwnd, hrgn, TRUE );
7617             ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
7618             DeleteObject( hrgn );
7619             GetClientRect( hwnd, &rect );
7620             ValidateRect( hwnd, &rect );  /* this will stop WM_PAINTs */
7621             ok( !count, "Got multiple WM_PAINTs\n" );
7622             if (++count > 10) break;
7623         }
7624     }
7625     DestroyWindow(hwnd);
7626 }
7627
7628
7629 static const struct message WmUser[] = {
7630     { WM_USER, sent },
7631     { 0 }
7632 };
7633
7634 struct sendmsg_info
7635 {
7636     HWND  hwnd;
7637     DWORD timeout;
7638     DWORD ret;
7639 };
7640
7641 static DWORD CALLBACK send_msg_thread( LPVOID arg )
7642 {
7643     struct sendmsg_info *info = arg;
7644     info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
7645     if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT, "unexpected error %d\n", GetLastError());
7646     return 0;
7647 }
7648
7649 static void wait_for_thread( HANDLE thread )
7650 {
7651     while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
7652     {
7653         MSG msg;
7654         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage(&msg);
7655     }
7656 }
7657
7658 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7659 {
7660     if (message == WM_USER) Sleep(200);
7661     return MsgCheckProcA( hwnd, message, wParam, lParam );
7662 }
7663
7664 static void test_SendMessageTimeout(void)
7665 {
7666     HANDLE thread;
7667     struct sendmsg_info info;
7668     DWORD tid;
7669
7670     info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
7671                                100, 100, 200, 200, 0, 0, 0, NULL);
7672     flush_events();
7673     flush_sequence();
7674
7675     info.timeout = 1000;
7676     info.ret = 0xdeadbeef;
7677     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
7678     wait_for_thread( thread );
7679     CloseHandle( thread );
7680     ok( info.ret == 1, "SendMessageTimeout failed\n" );
7681     ok_sequence( WmUser, "WmUser", FALSE );
7682
7683     info.timeout = 1;
7684     info.ret = 0xdeadbeef;
7685     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
7686     Sleep(100);  /* SendMessageTimeout should timeout here */
7687     wait_for_thread( thread );
7688     CloseHandle( thread );
7689     ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
7690     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
7691
7692     /* 0 means infinite timeout */
7693     info.timeout = 0;
7694     info.ret = 0xdeadbeef;
7695     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
7696     Sleep(100);
7697     wait_for_thread( thread );
7698     CloseHandle( thread );
7699     ok( info.ret == 1, "SendMessageTimeout failed\n" );
7700     ok_sequence( WmUser, "WmUser", FALSE );
7701
7702     /* timeout is treated as signed despite the prototype */
7703     info.timeout = 0x7fffffff;
7704     info.ret = 0xdeadbeef;
7705     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
7706     Sleep(100);
7707     wait_for_thread( thread );
7708     CloseHandle( thread );
7709     ok( info.ret == 1, "SendMessageTimeout failed\n" );
7710     ok_sequence( WmUser, "WmUser", FALSE );
7711
7712     info.timeout = 0x80000000;
7713     info.ret = 0xdeadbeef;
7714     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
7715     Sleep(100);
7716     wait_for_thread( thread );
7717     CloseHandle( thread );
7718     ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
7719     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
7720
7721     /* now check for timeout during message processing */
7722     SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
7723     info.timeout = 100;
7724     info.ret = 0xdeadbeef;
7725     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
7726     wait_for_thread( thread );
7727     CloseHandle( thread );
7728     /* we should timeout but still get the message */
7729     ok( info.ret == 0, "SendMessageTimeout failed\n" );
7730     ok_sequence( WmUser, "WmUser", FALSE );
7731
7732     DestroyWindow( info.hwnd );
7733 }
7734
7735
7736 /****************** edit message test *************************/
7737 #define ID_EDIT 0x1234
7738 static const struct message sl_edit_setfocus[] =
7739 {
7740     { HCBT_SETFOCUS, hook },
7741     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
7742     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
7743     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7744     { WM_SETFOCUS, sent|wparam, 0 },
7745     { WM_CTLCOLOREDIT, sent|parent },
7746     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7747     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7748     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
7749     { 0 }
7750 };
7751 static const struct message ml_edit_setfocus[] =
7752 {
7753     { HCBT_SETFOCUS, hook },
7754     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
7755     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
7756     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7757     { WM_SETFOCUS, sent|wparam, 0 },
7758     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7759     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7760     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7761     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
7762     { 0 }
7763 };
7764 static const struct message sl_edit_killfocus[] =
7765 {
7766     { HCBT_SETFOCUS, hook },
7767     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7768     { WM_KILLFOCUS, sent|wparam, 0 },
7769     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7770     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7771     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
7772     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
7773     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
7774     { 0 }
7775 };
7776 static const struct message sl_edit_lbutton_dblclk[] =
7777 {
7778     { WM_LBUTTONDBLCLK, sent },
7779     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
7780     { 0 }
7781 };
7782 static const struct message sl_edit_lbutton_down[] =
7783 {
7784     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
7785     { HCBT_SETFOCUS, hook },
7786     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
7787     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
7788     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7789     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
7790     { WM_CTLCOLOREDIT, sent|parent },
7791     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7792     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7793     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7794     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
7795     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
7796     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7797     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7798     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7799     { 0 }
7800 };
7801 static const struct message ml_edit_lbutton_down[] =
7802 {
7803     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
7804     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
7805     { HCBT_SETFOCUS, hook },
7806     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
7807     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
7808     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7809     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
7810     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7811     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7812     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
7813     { 0 }
7814 };
7815 static const struct message sl_edit_lbutton_up[] =
7816 {
7817     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
7818     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7819     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
7820     { WM_CAPTURECHANGED, sent|defwinproc },
7821     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7822     { 0 }
7823 };
7824 static const struct message ml_edit_lbutton_up[] =
7825 {
7826     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
7827     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
7828     { WM_CAPTURECHANGED, sent|defwinproc },
7829     { 0 }
7830 };
7831
7832 static WNDPROC old_edit_proc;
7833
7834 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7835 {
7836     static long defwndproc_counter = 0;
7837     LRESULT ret;
7838     struct message msg;
7839
7840     trace("edit: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
7841
7842     /* explicitly ignore WM_GETICON message */
7843     if (message == WM_GETICON) return 0;
7844
7845     msg.message = message;
7846     msg.flags = sent|wparam|lparam;
7847     if (defwndproc_counter) msg.flags |= defwinproc;
7848     msg.wParam = wParam;
7849     msg.lParam = lParam;
7850     add_message(&msg);
7851
7852     defwndproc_counter++;
7853     ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
7854     defwndproc_counter--;
7855
7856     return ret;
7857 }
7858
7859 static void subclass_edit(void)
7860 {
7861     WNDCLASSA cls;
7862
7863     if (!GetClassInfoA(0, "edit", &cls)) assert(0);
7864
7865     old_edit_proc = cls.lpfnWndProc;
7866
7867     cls.hInstance = GetModuleHandle(0);
7868     cls.lpfnWndProc = edit_hook_proc;
7869     cls.lpszClassName = "my_edit_class";
7870     UnregisterClass(cls.lpszClassName, cls.hInstance);
7871     if (!RegisterClassA(&cls)) assert(0);
7872 }
7873
7874 static void test_edit_messages(void)
7875 {
7876     HWND hwnd, parent;
7877     DWORD dlg_code;
7878
7879     subclass_edit();
7880     log_all_parent_messages++;
7881
7882     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7883                              100, 100, 200, 200, 0, 0, 0, NULL);
7884     ok (parent != 0, "Failed to create parent window\n");
7885
7886     /* test single line edit */
7887     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
7888                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
7889     ok(hwnd != 0, "Failed to create edit window\n");
7890
7891     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
7892     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
7893
7894     ShowWindow(hwnd, SW_SHOW);
7895     UpdateWindow(hwnd);
7896     SetFocus(0);
7897     flush_sequence();
7898
7899     SetFocus(hwnd);
7900     ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
7901
7902     SetFocus(0);
7903     ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
7904
7905     SetFocus(0);
7906     ReleaseCapture();
7907     flush_sequence();
7908
7909     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
7910     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
7911
7912     SetFocus(0);
7913     ReleaseCapture();
7914     flush_sequence();
7915
7916     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
7917     ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
7918
7919     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
7920     ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
7921
7922     DestroyWindow(hwnd);
7923
7924     /* test multiline edit */
7925     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
7926                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
7927     ok(hwnd != 0, "Failed to create edit window\n");
7928
7929     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
7930     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
7931        "wrong dlg_code %08x\n", dlg_code);
7932
7933     ShowWindow(hwnd, SW_SHOW);
7934     UpdateWindow(hwnd);
7935     SetFocus(0);
7936     flush_sequence();
7937
7938     SetFocus(hwnd);
7939     ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
7940
7941     SetFocus(0);
7942     ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
7943
7944     SetFocus(0);
7945     ReleaseCapture();
7946     flush_sequence();
7947
7948     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
7949     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
7950
7951     SetFocus(0);
7952     ReleaseCapture();
7953     flush_sequence();
7954
7955     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
7956     ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
7957
7958     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
7959     ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
7960
7961     DestroyWindow(hwnd);
7962     DestroyWindow(parent);
7963
7964     log_all_parent_messages--;
7965 }
7966
7967 /**************************** End of Edit test ******************************/
7968
7969 static const struct message WmKeyDownSkippedSeq[] =
7970 {
7971     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
7972     { 0 }
7973 };
7974 static const struct message WmKeyUpSkippedSeq[] =
7975 {
7976     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
7977     { 0 }
7978 };
7979
7980 #define EV_START_STOP 0
7981 #define EV_SENDMSG 1
7982 #define EV_ACK 2
7983
7984 struct peekmsg_info
7985 {
7986     HWND  hwnd;
7987     HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
7988 };
7989
7990 static DWORD CALLBACK send_msg_thread_2(void *param)
7991 {
7992     DWORD ret;
7993     struct peekmsg_info *info = param;
7994
7995     trace("thread: waiting for start\n");
7996     WaitForSingleObject(info->hevent[EV_START_STOP], INFINITE);
7997     trace("thread: looping\n");
7998
7999     while (1)
8000     {
8001         ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
8002
8003         switch (ret)
8004         {
8005         case WAIT_OBJECT_0 + EV_START_STOP:
8006             trace("thread: exiting\n");
8007             return 0;
8008
8009         case WAIT_OBJECT_0 + EV_SENDMSG:
8010             trace("thread: sending message\n");
8011             SendNotifyMessageA(info->hwnd, WM_USER, 0, 0);
8012             SetEvent(info->hevent[EV_ACK]);
8013             break;
8014
8015         default:
8016             trace("unexpected return: %04x\n", ret);
8017             assert(0);
8018             break;
8019         }
8020     }
8021     return 0;
8022 }
8023
8024 static void test_PeekMessage(void)
8025 {
8026     MSG msg;
8027     HANDLE hthread;
8028     DWORD tid, qstatus;
8029     UINT qs_all_input = QS_ALLINPUT;
8030     UINT qs_input = QS_INPUT;
8031     BOOL ret;
8032     struct peekmsg_info info;
8033
8034     info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8035                               100, 100, 200, 200, 0, 0, 0, NULL);
8036     assert(info.hwnd);
8037     ShowWindow(info.hwnd, SW_SHOW);
8038     UpdateWindow(info.hwnd);
8039     SetFocus(info.hwnd);
8040
8041     info.hevent[EV_START_STOP] = CreateEventA(NULL, 0, 0, NULL);
8042     info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
8043     info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
8044
8045     hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
8046     Sleep(100);
8047
8048     trace("signalling to start looping\n");
8049     SetEvent(info.hevent[EV_START_STOP]);
8050
8051     flush_events();
8052     flush_sequence();
8053
8054     SetLastError(0xdeadbeef);
8055     qstatus = GetQueueStatus(qs_all_input);
8056     if (GetLastError() == ERROR_INVALID_FLAGS)
8057     {
8058         trace("QS_RAWINPUT not supported on this platform\n");
8059         qs_all_input &= ~QS_RAWINPUT;
8060         qs_input &= ~QS_RAWINPUT;
8061     }
8062     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
8063
8064     trace("signalling to send message\n");
8065     SetEvent(info.hevent[EV_SENDMSG]);
8066     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8067
8068     /* pass invalid QS_xxxx flags */
8069     SetLastError(0xdeadbeef);
8070     qstatus = GetQueueStatus(0xffffffff);
8071     ok(qstatus == 0, "GetQueueStatus should fail: %08x\n", qstatus);
8072     ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
8073
8074     qstatus = GetQueueStatus(qs_all_input);
8075     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
8076        "wrong qstatus %08x\n", qstatus);
8077
8078     msg.message = 0;
8079     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8080     ok(!ret,
8081        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8082         msg.message);
8083     ok_sequence(WmUser, "WmUser", FALSE);
8084
8085     qstatus = GetQueueStatus(qs_all_input);
8086     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
8087
8088     keybd_event('N', 0, 0, 0);
8089     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8090     qstatus = GetQueueStatus(qs_all_input);
8091     ok(qstatus == MAKELONG(QS_KEY, QS_KEY),
8092        "wrong qstatus %08x\n", qstatus);
8093
8094     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
8095     qstatus = GetQueueStatus(qs_all_input);
8096     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
8097        "wrong qstatus %08x\n", qstatus);
8098
8099     InvalidateRect(info.hwnd, NULL, FALSE);
8100     qstatus = GetQueueStatus(qs_all_input);
8101     ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8102        "wrong qstatus %08x\n", qstatus);
8103
8104     trace("signalling to send message\n");
8105     SetEvent(info.hevent[EV_SENDMSG]);
8106     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8107
8108     qstatus = GetQueueStatus(qs_all_input);
8109     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8110        "wrong qstatus %08x\n", qstatus);
8111
8112     msg.message = 0;
8113     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
8114     ok(!ret,
8115        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8116         msg.message);
8117     ok_sequence(WmUser, "WmUser", FALSE);
8118
8119     qstatus = GetQueueStatus(qs_all_input);
8120     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8121        "wrong qstatus %08x\n", qstatus);
8122
8123     trace("signalling to send message\n");
8124     SetEvent(info.hevent[EV_SENDMSG]);
8125     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8126
8127     qstatus = GetQueueStatus(qs_all_input);
8128     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8129        "wrong qstatus %08x\n", qstatus);
8130
8131     msg.message = 0;
8132     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
8133     ok(!ret,
8134        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8135         msg.message);
8136     ok_sequence(WmUser, "WmUser", FALSE);
8137
8138     qstatus = GetQueueStatus(qs_all_input);
8139     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8140        "wrong qstatus %08x\n", qstatus);
8141
8142     msg.message = 0;
8143     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
8144     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
8145        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
8146        ret, msg.message, msg.wParam);
8147     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8148
8149     qstatus = GetQueueStatus(qs_all_input);
8150     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
8151        "wrong qstatus %08x\n", qstatus);
8152
8153     msg.message = 0;
8154     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
8155     ok(!ret,
8156        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8157         msg.message);
8158     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8159
8160     qstatus = GetQueueStatus(qs_all_input);
8161     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
8162        "wrong qstatus %08x\n", qstatus);
8163
8164     msg.message = 0;
8165     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
8166     ok(ret && msg.message == WM_PAINT,
8167        "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
8168     DispatchMessageA(&msg);
8169     ok_sequence(WmPaint, "WmPaint", FALSE);
8170
8171     qstatus = GetQueueStatus(qs_all_input);
8172     ok(qstatus == MAKELONG(0, QS_KEY),
8173        "wrong qstatus %08x\n", qstatus);
8174
8175     msg.message = 0;
8176     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
8177     ok(!ret,
8178        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8179         msg.message);
8180     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8181
8182     qstatus = GetQueueStatus(qs_all_input);
8183     ok(qstatus == MAKELONG(0, QS_KEY),
8184        "wrong qstatus %08x\n", qstatus);
8185
8186     trace("signalling to send message\n");
8187     SetEvent(info.hevent[EV_SENDMSG]);
8188     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8189
8190     qstatus = GetQueueStatus(qs_all_input);
8191     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
8192        "wrong qstatus %08x\n", qstatus);
8193
8194     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
8195
8196     qstatus = GetQueueStatus(qs_all_input);
8197     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
8198        "wrong qstatus %08x\n", qstatus);
8199
8200     msg.message = 0;
8201     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
8202     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
8203        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
8204        ret, msg.message, msg.wParam);
8205     ok_sequence(WmUser, "WmUser", FALSE);
8206
8207     qstatus = GetQueueStatus(qs_all_input);
8208     ok(qstatus == MAKELONG(0, QS_KEY),
8209        "wrong qstatus %08x\n", qstatus);
8210
8211     msg.message = 0;
8212     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
8213     ok(!ret,
8214        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8215         msg.message);
8216     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8217
8218     qstatus = GetQueueStatus(qs_all_input);
8219     ok(qstatus == MAKELONG(0, QS_KEY),
8220        "wrong qstatus %08x\n", qstatus);
8221
8222     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
8223
8224     qstatus = GetQueueStatus(qs_all_input);
8225     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
8226        "wrong qstatus %08x\n", qstatus);
8227
8228     trace("signalling to send message\n");
8229     SetEvent(info.hevent[EV_SENDMSG]);
8230     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8231
8232     qstatus = GetQueueStatus(qs_all_input);
8233     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
8234        "wrong qstatus %08x\n", qstatus);
8235
8236     msg.message = 0;
8237     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
8238     ok(!ret,
8239        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8240         msg.message);
8241     ok_sequence(WmUser, "WmUser", FALSE);
8242
8243     qstatus = GetQueueStatus(qs_all_input);
8244     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
8245        "wrong qstatus %08x\n", qstatus);
8246
8247     msg.message = 0;
8248     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
8249         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
8250     else /* workaround for a missing QS_RAWINPUT support */
8251         ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
8252     ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
8253        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
8254        ret, msg.message, msg.wParam);
8255     ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
8256
8257     qstatus = GetQueueStatus(qs_all_input);
8258     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
8259        "wrong qstatus %08x\n", qstatus);
8260
8261     msg.message = 0;
8262     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
8263         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
8264     else /* workaround for a missing QS_RAWINPUT support */
8265         ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
8266     ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
8267        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYUP wParam 'N'\n",
8268        ret, msg.message, msg.wParam);
8269     ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
8270
8271     qstatus = GetQueueStatus(qs_all_input);
8272     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
8273        "wrong qstatus %08x\n", qstatus);
8274
8275     msg.message = 0;
8276     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
8277     ok(!ret,
8278        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8279         msg.message);
8280     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8281
8282     qstatus = GetQueueStatus(qs_all_input);
8283     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
8284        "wrong qstatus %08x\n", qstatus);
8285
8286     msg.message = 0;
8287     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8288     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
8289        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
8290        ret, msg.message, msg.wParam);
8291     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8292
8293     qstatus = GetQueueStatus(qs_all_input);
8294     ok(qstatus == 0,
8295        "wrong qstatus %08x\n", qstatus);
8296
8297     msg.message = 0;
8298     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8299     ok(!ret,
8300        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8301         msg.message);
8302     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8303
8304     qstatus = GetQueueStatus(qs_all_input);
8305     ok(qstatus == 0,
8306        "wrong qstatus %08x\n", qstatus);
8307
8308     /* test whether presence of the quit flag in the queue affects
8309      * the queue state
8310      */
8311     PostQuitMessage(0x1234abcd);
8312
8313     qstatus = GetQueueStatus(qs_all_input);
8314     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
8315        "wrong qstatus %08x\n", qstatus);
8316
8317     PostMessageA(info.hwnd, WM_USER, 0, 0);
8318
8319     qstatus = GetQueueStatus(qs_all_input);
8320     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
8321        "wrong qstatus %08x\n", qstatus);
8322
8323     msg.message = 0;
8324     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8325     ok(ret && msg.message == WM_USER,
8326        "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
8327     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8328
8329     qstatus = GetQueueStatus(qs_all_input);
8330     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
8331        "wrong qstatus %08x\n", qstatus);
8332
8333     msg.message = 0;
8334     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8335     ok(ret && msg.message == WM_QUIT,
8336        "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
8337     ok(msg.wParam == 0x1234abcd, "got wParam %08lx instead of 0x1234abcd\n", msg.wParam);
8338     ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
8339     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8340
8341     qstatus = GetQueueStatus(qs_all_input);
8342 todo_wine {
8343     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
8344        "wrong qstatus %08x\n", qstatus);
8345 }
8346
8347     msg.message = 0;
8348     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8349     ok(!ret,
8350        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8351         msg.message);
8352     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8353
8354     qstatus = GetQueueStatus(qs_all_input);
8355     ok(qstatus == 0,
8356        "wrong qstatus %08x\n", qstatus);
8357
8358     trace("signalling to exit\n");
8359     SetEvent(info.hevent[EV_START_STOP]);
8360
8361     WaitForSingleObject(hthread, INFINITE);
8362
8363     CloseHandle(hthread);
8364     CloseHandle(info.hevent[0]);
8365     CloseHandle(info.hevent[1]);
8366     CloseHandle(info.hevent[2]);
8367
8368     DestroyWindow(info.hwnd);
8369 }
8370
8371
8372 static void test_quit_message(void)
8373 {
8374     MSG msg;
8375     BOOL ret;
8376
8377     /* test using PostQuitMessage */
8378     PostQuitMessage(0xbeef);
8379
8380     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
8381     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
8382     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
8383     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
8384
8385     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
8386     ok(ret, "PostMessage failed with error %d\n", GetLastError());
8387
8388     ret = GetMessage(&msg, NULL, 0, 0);
8389     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
8390     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
8391
8392     /* note: WM_QUIT message received after WM_USER message */
8393     ret = GetMessage(&msg, NULL, 0, 0);
8394     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
8395     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
8396     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
8397
8398     ret = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
8399     ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
8400
8401     /* now test with PostThreadMessage - different behaviour! */
8402     PostThreadMessage(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
8403
8404     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
8405     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
8406     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
8407     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
8408
8409     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
8410     ok(ret, "PostMessage failed with error %d\n", GetLastError());
8411
8412     /* note: we receive the WM_QUIT message first this time */
8413     ret = GetMessage(&msg, NULL, 0, 0);
8414     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
8415     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
8416     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
8417
8418     ret = GetMessage(&msg, NULL, 0, 0);
8419     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
8420     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
8421 }
8422
8423 static const struct message WmMouseHoverSeq[] = {
8424     { WM_MOUSEACTIVATE, sent|optional },  /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
8425     { WM_MOUSEACTIVATE, sent|optional },
8426     { WM_TIMER, sent|optional }, /* XP sends it */
8427     { WM_SYSTIMER, sent },
8428     { WM_MOUSEHOVER, sent|wparam, 0 },
8429     { 0 }
8430 };
8431
8432 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
8433 {
8434     MSG msg;
8435     DWORD start_ticks, end_ticks;
8436
8437     start_ticks = GetTickCount();
8438     /* add some deviation (5%) to cover not expected delays */
8439     start_ticks += timeout / 20;
8440
8441     do
8442     {
8443         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
8444         {
8445             /* Timer proc messages are not dispatched to the window proc,
8446              * and therefore not logged.
8447              */
8448             if (msg.message == WM_TIMER || msg.message == WM_SYSTIMER)
8449             {
8450                 struct message s_msg;
8451
8452                 s_msg.message = msg.message;
8453                 s_msg.flags = sent|wparam|lparam;
8454                 s_msg.wParam = msg.wParam;
8455                 s_msg.lParam = msg.lParam;
8456                 add_message(&s_msg);
8457             }
8458             DispatchMessage(&msg);
8459         }
8460
8461         end_ticks = GetTickCount();
8462
8463         /* inject WM_MOUSEMOVE to see how it changes tracking */
8464         if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
8465         {
8466             mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8467             mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8468
8469             inject_mouse_move = FALSE;
8470         }
8471     } while (start_ticks + timeout >= end_ticks);
8472 }
8473
8474 static void test_TrackMouseEvent(void)
8475 {
8476     TRACKMOUSEEVENT tme;
8477     BOOL ret;
8478     HWND hwnd, hchild;
8479     RECT rc_parent, rc_child;
8480     UINT default_hover_time, hover_width = 0, hover_height = 0;
8481
8482 #define track_hover(track_hwnd, track_hover_time) \
8483     tme.cbSize = sizeof(tme); \
8484     tme.dwFlags = TME_HOVER; \
8485     tme.hwndTrack = track_hwnd; \
8486     tme.dwHoverTime = track_hover_time; \
8487     SetLastError(0xdeadbeef); \
8488     ret = pTrackMouseEvent(&tme); \
8489     ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
8490
8491 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
8492     tme.cbSize = sizeof(tme); \
8493     tme.dwFlags = TME_QUERY; \
8494     tme.hwndTrack = (HWND)0xdeadbeef; \
8495     tme.dwHoverTime = 0xdeadbeef; \
8496     SetLastError(0xdeadbeef); \
8497     ret = pTrackMouseEvent(&tme); \
8498     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
8499     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
8500     ok(tme.dwFlags == (expected_track_flags), \
8501        "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
8502     ok(tme.hwndTrack == (expected_track_hwnd), \
8503        "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
8504     ok(tme.dwHoverTime == (expected_hover_time), \
8505        "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
8506
8507 #define track_hover_cancel(track_hwnd) \
8508     tme.cbSize = sizeof(tme); \
8509     tme.dwFlags = TME_HOVER | TME_CANCEL; \
8510     tme.hwndTrack = track_hwnd; \
8511     tme.dwHoverTime = 0xdeadbeef; \
8512     SetLastError(0xdeadbeef); \
8513     ret = pTrackMouseEvent(&tme); \
8514     ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
8515
8516     default_hover_time = 0xdeadbeef;
8517     SetLastError(0xdeadbeef);
8518     ret = SystemParametersInfo(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
8519     ok(ret, "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
8520     if (!ret) default_hover_time = 400;
8521     trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
8522
8523     SetLastError(0xdeadbeef);
8524     ret = SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
8525     ok(ret, "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
8526     if (!ret) hover_width = 4;
8527     SetLastError(0xdeadbeef);
8528     ret = SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
8529     ok(ret, "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
8530     if (!ret) hover_height = 4;
8531     trace("hover rect is %u x %d\n", hover_width, hover_height);
8532
8533     hwnd = CreateWindowEx(0, "TestWindowClass", NULL,
8534                           WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8535                           CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
8536                           NULL, NULL, 0);
8537     assert(hwnd);
8538
8539     hchild = CreateWindowEx(0, "TestWindowClass", NULL,
8540                           WS_CHILD | WS_BORDER | WS_VISIBLE,
8541                           50, 50, 200, 200, hwnd,
8542                           NULL, NULL, 0);
8543     assert(hchild);
8544
8545     flush_events();
8546     flush_sequence();
8547
8548     tme.cbSize = 0;
8549     tme.dwFlags = TME_QUERY;
8550     tme.hwndTrack = (HWND)0xdeadbeef;
8551     tme.dwHoverTime = 0xdeadbeef;
8552     SetLastError(0xdeadbeef);
8553     ret = pTrackMouseEvent(&tme);
8554     ok(!ret, "TrackMouseEvent should fail\n");
8555     ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
8556
8557     tme.cbSize = sizeof(tme);
8558     tme.dwFlags = TME_HOVER;
8559     tme.hwndTrack = (HWND)0xdeadbeef;
8560     tme.dwHoverTime = 0xdeadbeef;
8561     SetLastError(0xdeadbeef);
8562     ret = pTrackMouseEvent(&tme);
8563     ok(!ret, "TrackMouseEvent should fail\n");
8564     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "not expected error %d\n", GetLastError());
8565
8566     tme.cbSize = sizeof(tme);
8567     tme.dwFlags = TME_HOVER | TME_CANCEL;
8568     tme.hwndTrack = (HWND)0xdeadbeef;
8569     tme.dwHoverTime = 0xdeadbeef;
8570     SetLastError(0xdeadbeef);
8571     ret = pTrackMouseEvent(&tme);
8572     ok(!ret, "TrackMouseEvent should fail\n");
8573     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "not expected error %d\n", GetLastError());
8574
8575     GetWindowRect(hwnd, &rc_parent);
8576     GetWindowRect(hchild, &rc_child);
8577     SetCursorPos(rc_child.left - 10, rc_child.top - 10);
8578
8579     /* Process messages so that the system updates its internal current
8580      * window and hittest, otherwise TrackMouseEvent calls don't have any
8581      * effect.
8582      */
8583     flush_events();
8584     flush_sequence();
8585
8586     track_query(0, NULL, 0);
8587     track_hover(hchild, 0);
8588     track_query(0, NULL, 0);
8589
8590     flush_events();
8591     flush_sequence();
8592
8593     track_hover(hwnd, 0);
8594     track_query(TME_HOVER, hwnd, default_hover_time);
8595
8596     pump_msg_loop_timeout(default_hover_time, FALSE);
8597     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
8598
8599     track_query(0, NULL, 0);
8600
8601     track_hover(hwnd, HOVER_DEFAULT);
8602     track_query(TME_HOVER, hwnd, default_hover_time);
8603
8604     Sleep(default_hover_time / 2);
8605     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8606     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8607
8608     track_query(TME_HOVER, hwnd, default_hover_time);
8609
8610     pump_msg_loop_timeout(default_hover_time / 2, FALSE);
8611     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
8612
8613     track_query(0, NULL, 0);
8614
8615     track_hover(hwnd, HOVER_DEFAULT);
8616     track_query(TME_HOVER, hwnd, default_hover_time);
8617
8618     pump_msg_loop_timeout(default_hover_time, TRUE);
8619     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
8620
8621     track_query(0, NULL, 0);
8622
8623     track_hover(hwnd, HOVER_DEFAULT);
8624     track_query(TME_HOVER, hwnd, default_hover_time);
8625     track_hover_cancel(hwnd);
8626
8627     DestroyWindow(hwnd);
8628
8629 #undef track_hover
8630 #undef track_query
8631 #undef track_hover_cancel
8632 }
8633
8634
8635 static const struct message WmSetWindowRgn[] = {
8636     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
8637     { WM_NCCALCSIZE, sent|wparam, 1 },
8638     { WM_NCPAINT, sent }, /* wparam != 1 */
8639     { WM_GETTEXT, sent|defwinproc|optional },
8640     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
8641     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
8642     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
8643     { 0 }
8644 };
8645
8646 static const struct message WmSetWindowRgn_no_redraw[] = {
8647     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
8648     { WM_NCCALCSIZE, sent|wparam, 1 },
8649     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
8650     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
8651     { 0 }
8652 };
8653
8654 static const struct message WmSetWindowRgn_clear[] = {
8655     { 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 */
8656     { WM_NCCALCSIZE, sent|wparam, 1 },
8657     { WM_NCPAINT, sent }, /* wparam != 1 */
8658     { WM_GETTEXT, sent|defwinproc|optional },
8659     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
8660     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
8661     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
8662     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
8663     { WM_GETTEXT, sent|defwinproc|optional },
8664     { WM_ERASEBKGND, sent|optional },
8665     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
8666     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
8667     { 0 }
8668 };
8669
8670 static void test_SetWindowRgn(void)
8671 {
8672     HRGN hrgn;
8673     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
8674                                 100, 100, 200, 200, 0, 0, 0, NULL);
8675     ok( hwnd != 0, "Failed to create overlapped window\n" );
8676
8677     ShowWindow( hwnd, SW_SHOW );
8678     UpdateWindow( hwnd );
8679     flush_events();
8680     flush_sequence();
8681
8682     trace("testing SetWindowRgn\n");
8683     hrgn = CreateRectRgn( 0, 0, 150, 150 );
8684     SetWindowRgn( hwnd, hrgn, TRUE );
8685     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
8686
8687     hrgn = CreateRectRgn( 30, 30, 160, 160 );
8688     SetWindowRgn( hwnd, hrgn, FALSE );
8689     ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
8690
8691     hrgn = CreateRectRgn( 0, 0, 180, 180 );
8692     SetWindowRgn( hwnd, hrgn, TRUE );
8693     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
8694
8695     SetWindowRgn( hwnd, 0, TRUE );
8696     ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
8697
8698     DestroyWindow( hwnd );
8699 }
8700
8701 /*************************** ShowWindow() test ******************************/
8702 static const struct message WmShowNormal[] = {
8703     { WM_SHOWWINDOW, sent|wparam, 1 },
8704     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
8705     { HCBT_ACTIVATE, hook },
8706     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
8707     { HCBT_SETFOCUS, hook },
8708     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
8709     { 0 }
8710 };
8711 static const struct message WmShow[] = {
8712     { WM_SHOWWINDOW, sent|wparam, 1 },
8713     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
8714     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
8715     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
8716     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
8717     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
8718     { 0 }
8719 };
8720 static const struct message WmShowNoActivate_1[] = {
8721     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
8722     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|0x8000 },
8723     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|0x8000 },
8724     { WM_MOVE, sent|defwinproc },
8725     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
8726     { 0 }
8727 };
8728 static const struct message WmShowNoActivate_2[] = {
8729     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
8730     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8731     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8732     { WM_MOVE, sent|defwinproc },
8733     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
8734     { HCBT_SETFOCUS, hook },
8735     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
8736     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
8737     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
8738     { 0 }
8739 };
8740 static const struct message WmShowNA_1[] = {
8741     { WM_SHOWWINDOW, sent|wparam, 1 },
8742     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
8743     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
8744     { 0 }
8745 };
8746 static const struct message WmShowNA_2[] = {
8747     { WM_SHOWWINDOW, sent|wparam, 1 },
8748     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
8749     { 0 }
8750 };
8751 static const struct message WmRestore_1[] = {
8752     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
8753     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8754     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
8755     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
8756     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
8757     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8758     { WM_MOVE, sent|defwinproc },
8759     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
8760     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
8761     { 0 }
8762 };
8763 static const struct message WmRestore_2[] = {
8764     { WM_SHOWWINDOW, sent|wparam, 1 },
8765     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
8766     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
8767     { 0 }
8768 };
8769 static const struct message WmRestore_3[] = {
8770     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
8771     { WM_GETMINMAXINFO, sent },
8772     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8773     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
8774     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
8775     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
8776     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8777     { WM_MOVE, sent|defwinproc },
8778     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
8779     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
8780     { 0 }
8781 };
8782 static const struct message WmRestore_4[] = {
8783     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
8784     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
8785     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|0x8000 },
8786     { WM_MOVE, sent|defwinproc },
8787     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
8788     { 0 }
8789 };
8790 static const struct message WmRestore_5[] = {
8791     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
8792     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
8793     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|0x8000 },
8794     { WM_MOVE, sent|defwinproc },
8795     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
8796     { 0 }
8797 };
8798 static const struct message WmHide_1[] = {
8799     { WM_SHOWWINDOW, sent|wparam, 0 },
8800     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
8801     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
8802     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
8803     { 0 }
8804 };
8805 static const struct message WmHide_2[] = {
8806     { WM_SHOWWINDOW, sent|wparam, 0 },
8807     { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
8808     { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
8809     { 0 }
8810 };
8811 static const struct message WmHide_3[] = {
8812     { WM_SHOWWINDOW, sent|wparam, 0 },
8813     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
8814     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
8815     { HCBT_SETFOCUS, hook },
8816     { 0 }
8817 };
8818 static const struct message WmShowMinimized_1[] = {
8819     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
8820     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8821     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
8822     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
8823     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8824     { WM_MOVE, sent|defwinproc },
8825     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
8826     { 0 }
8827 };
8828 static const struct message WmMinimize_1[] = {
8829     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
8830     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
8831     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8832     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8833     { WM_MOVE, sent|defwinproc },
8834     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
8835     { 0 }
8836 };
8837 static const struct message WmMinimize_2[] = {
8838     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
8839     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8840     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8841     { WM_MOVE, sent|defwinproc },
8842     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
8843     { 0 }
8844 };
8845 static const struct message WmMinimize_3[] = {
8846     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
8847     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8848     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8849     { WM_MOVE, sent|defwinproc },
8850     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
8851     { 0 }
8852 };
8853 static const struct message WmShowMinNoActivate[] = {
8854     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
8855     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
8856     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
8857     { 0 }
8858 };
8859 static const struct message WmMinMax_1[] = {
8860     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
8861     { 0 }
8862 };
8863 static const struct message WmMinMax_2[] = {
8864     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
8865     { 0 }
8866 };
8867 static const struct message WmMinMax_3[] = {
8868     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
8869     { 0 }
8870 };
8871 static const struct message WmMinMax_4[] = {
8872     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
8873     { 0 }
8874 };
8875 static const struct message WmShowMaximized_1[] = {
8876     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
8877     { WM_GETMINMAXINFO, sent },
8878     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8879     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
8880     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
8881     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
8882     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8883     { WM_MOVE, sent|defwinproc },
8884     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
8885     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
8886     { 0 }
8887 };
8888 static const struct message WmShowMaximized_2[] = {
8889     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
8890     { WM_GETMINMAXINFO, sent },
8891     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
8892     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
8893     { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
8894     { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
8895     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8896     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
8897     { WM_MOVE, sent|defwinproc },
8898     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
8899     { HCBT_SETFOCUS, hook },
8900     { 0 }
8901 };
8902 static const struct message WmShowMaximized_3[] = {
8903     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
8904     { WM_GETMINMAXINFO, sent },
8905     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
8906     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|0x8000 },
8907     { WM_MOVE, sent|defwinproc },
8908     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
8909     { 0 }
8910 };
8911
8912 static void test_ShowWindow(void)
8913 {
8914     /* ShowWindow commands in random order */
8915     static const struct
8916     {
8917         INT cmd; /* ShowWindow command */
8918         LPARAM ret; /* ShowWindow return value */
8919         DWORD style; /* window style after the command */
8920         const struct message *msg; /* message sequence the command produces */
8921         BOOL todo_msg; /* message sequence doesn't match what Wine does */
8922     } sw[] =
8923     {
8924 /*  1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal, FALSE },
8925 /*  2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
8926 /*  3 */ { SW_HIDE, TRUE, 0, WmHide_1, FALSE },
8927 /*  4 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
8928 /*  5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1, FALSE },
8929 /*  6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1, FALSE },
8930 /*  7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1, FALSE },
8931 /*  8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
8932 /*  9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1, FALSE },
8933 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2, FALSE },
8934 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1, FALSE },
8935 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq, FALSE },
8936 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1, FALSE },
8937 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
8938 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2, FALSE },
8939 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
8940 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow, FALSE },
8941 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
8942 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1, TRUE },
8943 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
8944 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
8945 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate, TRUE },
8946 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4, FALSE },
8947 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
8948 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
8949 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1, FALSE },
8950 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2, FALSE },
8951 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
8952 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
8953 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1, FALSE },
8954 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
8955 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3, TRUE },
8956 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
8957 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, TRUE }, /* what does this mean?! */
8958 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, TRUE },
8959 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
8960 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2, FALSE },
8961 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
8962 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
8963 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2, TRUE },
8964 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
8965 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2, TRUE },
8966 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2, FALSE },
8967 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1, TRUE },
8968 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
8969 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3, FALSE },
8970 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4, FALSE },
8971 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3, FALSE },
8972 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq, FALSE },
8973 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5, FALSE },
8974 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
8975 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1, FALSE },
8976 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
8977 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3, TRUE },
8978 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
8979 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2, FALSE },
8980 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq, FALSE }
8981     };
8982     HWND hwnd;
8983     DWORD style;
8984     LPARAM ret;
8985     INT i;
8986
8987 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
8988     hwnd = CreateWindowEx(0, "ShowWindowClass", NULL, WS_BASE,
8989                           120, 120, 90, 90,
8990                           0, 0, 0, NULL);
8991     assert(hwnd);
8992
8993     style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
8994     ok(style == 0, "expected style 0, got %08x\n", style);
8995
8996     flush_events();
8997     flush_sequence();
8998
8999     for (i = 0; i < sizeof(sw)/sizeof(sw[0]); i++)
9000     {
9001         static const char * const sw_cmd_name[13] =
9002         {
9003             "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
9004             "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
9005             "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
9006             "SW_NORMALNA" /* 0xCC */
9007         };
9008         char comment[64];
9009         INT idx; /* index into the above array of names */
9010
9011         idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
9012
9013         style = GetWindowLong(hwnd, GWL_STYLE);
9014         trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
9015         ret = ShowWindow(hwnd, sw[i].cmd);
9016         ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
9017         style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
9018         ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
9019
9020         sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
9021         ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
9022
9023         flush_events();
9024         flush_sequence();
9025     }
9026
9027     DestroyWindow(hwnd);
9028 }
9029
9030 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9031 {
9032     struct message msg;
9033
9034     trace("dialog: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
9035
9036     switch (message)
9037     {
9038     case WM_WINDOWPOSCHANGING:
9039     case WM_WINDOWPOSCHANGED:
9040     {
9041         WINDOWPOS *winpos = (WINDOWPOS *)lParam;
9042
9043         trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
9044         trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
9045               winpos->hwnd, winpos->hwndInsertAfter,
9046               winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
9047         dump_winpos_flags(winpos->flags);
9048
9049         /* Log only documented flags, win2k uses 0x1000 and 0x2000
9050          * in the high word for internal purposes
9051          */
9052         wParam = winpos->flags & 0xffff;
9053         /* We are not interested in the flags that don't match under XP and Win9x */
9054         wParam &= ~(SWP_NOZORDER);
9055         break;
9056     }
9057
9058     /* explicitly ignore WM_GETICON message */
9059     case WM_GETICON:
9060         return 0;
9061     }
9062
9063     msg.message = message;
9064     msg.flags = sent|wparam|lparam;
9065     msg.wParam = wParam;
9066     msg.lParam = lParam;
9067     add_message(&msg);
9068
9069     /* calling DefDlgProc leads to a recursion under XP */
9070
9071     switch (message)
9072     {
9073     case WM_INITDIALOG:
9074     case WM_GETDLGCODE:
9075         return 0;
9076     }
9077     return 1;
9078 }
9079
9080 static const struct message WmDefDlgSetFocus_1[] = {
9081     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
9082     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
9083     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
9084     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
9085     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
9086     { HCBT_SETFOCUS, hook },
9087     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
9088     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9089     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9090     { WM_SETFOCUS, sent|wparam, 0 },
9091     { WM_CTLCOLOREDIT, sent },
9092     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9093     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9094     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9095     { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
9096     { 0 }
9097 };
9098 static const struct message WmDefDlgSetFocus_2[] = {
9099     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
9100     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
9101     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
9102     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
9103     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
9104     { WM_CTLCOLOREDIT, sent|optional }, /* XP */
9105     { 0 }
9106 };
9107 /* Creation of a dialog */
9108 static const struct message WmCreateDialogParamSeq_1[] = {
9109     { HCBT_CREATEWND, hook },
9110     { WM_NCCREATE, sent },
9111     { WM_NCCALCSIZE, sent|wparam, 0 },
9112     { WM_CREATE, sent },
9113     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
9114     { WM_SIZE, sent|wparam, SIZE_RESTORED },
9115     { WM_MOVE, sent },
9116     { WM_SETFONT, sent },
9117     { WM_INITDIALOG, sent },
9118     { WM_CHANGEUISTATE, sent|optional },
9119     { 0 }
9120 };
9121 /* Creation of a dialog */
9122 static const struct message WmCreateDialogParamSeq_2[] = {
9123     { HCBT_CREATEWND, hook },
9124     { WM_NCCREATE, sent },
9125     { WM_NCCALCSIZE, sent|wparam, 0 },
9126     { WM_CREATE, sent },
9127     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
9128     { WM_SIZE, sent|wparam, SIZE_RESTORED },
9129     { WM_MOVE, sent },
9130     { WM_CHANGEUISTATE, sent|optional },
9131     { 0 }
9132 };
9133
9134 static void test_dialog_messages(void)
9135 {
9136     WNDCLASS cls;
9137     HWND hdlg, hedit1, hedit2, hfocus;
9138     LRESULT ret;
9139
9140 #define set_selection(hctl, start, end) \
9141     ret = SendMessage(hctl, EM_SETSEL, start, end); \
9142     ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
9143
9144 #define check_selection(hctl, start, end) \
9145     ret = SendMessage(hctl, EM_GETSEL, 0, 0); \
9146     ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
9147
9148     subclass_edit();
9149
9150     hdlg = CreateWindowEx(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
9151                           WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
9152                           0, 0, 100, 100, 0, 0, 0, NULL);
9153     ok(hdlg != 0, "Failed to create custom dialog window\n");
9154
9155     hedit1 = CreateWindowEx(0, "my_edit_class", NULL,
9156                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
9157                            0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
9158     ok(hedit1 != 0, "Failed to create edit control\n");
9159     hedit2 = CreateWindowEx(0, "my_edit_class", NULL,
9160                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
9161                            0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
9162     ok(hedit2 != 0, "Failed to create edit control\n");
9163
9164     SendMessage(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
9165     SendMessage(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
9166
9167     hfocus = GetFocus();
9168     ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
9169
9170     SetFocus(hedit2);
9171     hfocus = GetFocus();
9172     ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
9173
9174     check_selection(hedit1, 0, 0);
9175     check_selection(hedit2, 0, 0);
9176
9177     set_selection(hedit2, 0, -1);
9178     check_selection(hedit2, 0, 3);
9179
9180     SetFocus(0);
9181     hfocus = GetFocus();
9182     ok(hfocus == 0, "wrong focus %p\n", hfocus);
9183
9184     flush_sequence();
9185     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
9186     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
9187     ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
9188
9189     hfocus = GetFocus();
9190     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
9191
9192     check_selection(hedit1, 0, 5);
9193     check_selection(hedit2, 0, 3);
9194
9195     flush_sequence();
9196     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
9197     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
9198     ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
9199
9200     hfocus = GetFocus();
9201     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
9202
9203     check_selection(hedit1, 0, 5);
9204     check_selection(hedit2, 0, 3);
9205
9206     EndDialog(hdlg, 0);
9207     DestroyWindow(hedit1);
9208     DestroyWindow(hedit2);
9209     DestroyWindow(hdlg);
9210     flush_sequence();
9211
9212 #undef set_selection
9213 #undef check_selection
9214
9215     ok(GetClassInfo(0, "#32770", &cls), "GetClassInfo failed\n");
9216     cls.lpszClassName = "MyDialogClass";
9217     cls.hInstance = GetModuleHandle(0);
9218     /* need a cast since a dlgproc is used as a wndproc */
9219     cls.lpfnWndProc = (WNDPROC)test_dlg_proc;
9220     if (!RegisterClass(&cls)) assert(0);
9221
9222     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
9223     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
9224     ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
9225     EndDialog(hdlg, 0);
9226     DestroyWindow(hdlg);
9227     flush_sequence();
9228
9229     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
9230     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
9231     ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
9232     EndDialog(hdlg, 0);
9233     DestroyWindow(hdlg);
9234     flush_sequence();
9235
9236     UnregisterClass(cls.lpszClassName, cls.hInstance);
9237 }
9238
9239 static void test_nullCallback(void)
9240 {
9241     HWND hwnd;
9242
9243     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
9244                            100, 100, 200, 200, 0, 0, 0, NULL);
9245     ok (hwnd != 0, "Failed to create overlapped window\n");
9246
9247     SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
9248     flush_events();
9249     DestroyWindow(hwnd);
9250 }
9251
9252 static const struct message SetForegroundWindowSeq[] =
9253 {
9254     { WM_NCACTIVATE, sent|wparam, 0 },
9255     { WM_GETTEXT, sent|defwinproc|optional },
9256     { WM_ACTIVATE, sent|wparam, 0 },
9257     { WM_ACTIVATEAPP, sent|wparam, 0 },
9258     { WM_KILLFOCUS, sent },
9259     { 0 }
9260 };
9261
9262 static void test_SetForegroundWindow(void)
9263 {
9264     HWND hwnd;
9265
9266     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
9267                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9268                            100, 100, 200, 200, 0, 0, 0, NULL);
9269     ok (hwnd != 0, "Failed to create overlapped window\n");
9270     flush_sequence();
9271
9272     trace("SetForegroundWindow( 0 )\n");
9273     SetForegroundWindow( 0 );
9274     ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
9275     trace("SetForegroundWindow( GetDesktopWindow() )\n");
9276     SetForegroundWindow( GetDesktopWindow() );
9277     ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
9278                                         "foreground top level window", FALSE);
9279     trace("done\n");
9280
9281     DestroyWindow(hwnd);
9282 }
9283
9284 static void test_dbcs_wm_char(void)
9285 {
9286     BYTE dbch[2];
9287     WCHAR wch, bad_wch;
9288     HWND hwnd, hwnd2;
9289     MSG msg;
9290     DWORD time;
9291     POINT pt;
9292     DWORD_PTR res;
9293     CPINFOEXA cpinfo;
9294     UINT i, j, k;
9295     struct message wmCharSeq[2];
9296
9297     pGetCPInfoExA( CP_ACP, 0, &cpinfo );
9298     if (cpinfo.MaxCharSize != 2)
9299     {
9300         skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
9301         return;
9302     }
9303
9304     dbch[0] = dbch[1] = 0;
9305     wch = 0;
9306     bad_wch = cpinfo.UnicodeDefaultChar;
9307     for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
9308         for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
9309             for (k = 128; k <= 255; k++)
9310             {
9311                 char str[2];
9312                 WCHAR wstr[2];
9313                 str[0] = j;
9314                 str[1] = k;
9315                 if (MultiByteToWideChar( CP_ACP, 0, str, 2, wstr, 2 ) == 1 &&
9316                     WideCharToMultiByte( CP_ACP, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
9317                     (BYTE)str[0] == j && (BYTE)str[1] == k &&
9318                     HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
9319                 {
9320                     dbch[0] = j;
9321                     dbch[1] = k;
9322                     wch = wstr[0];
9323                     break;
9324                 }
9325             }
9326
9327     if (!wch)
9328     {
9329         skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
9330         return;
9331     }
9332     trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
9333            dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
9334
9335     hwnd = CreateWindowExW(0, testWindowClassW, NULL,
9336                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
9337     hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
9338                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
9339     ok (hwnd != 0, "Failed to create overlapped window\n");
9340     ok (hwnd2 != 0, "Failed to create overlapped window\n");
9341     flush_sequence();
9342
9343     memset( wmCharSeq, 0, sizeof(wmCharSeq) );
9344     wmCharSeq[0].message = WM_CHAR;
9345     wmCharSeq[0].flags = sent|wparam;
9346     wmCharSeq[0].wParam = wch;
9347
9348     /* posted message */
9349     PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
9350     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9351     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
9352     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
9353     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9354     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
9355     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9356
9357     /* posted thread message */
9358     PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
9359     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9360     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
9361     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
9362     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9363     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
9364     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9365
9366     /* sent message */
9367     flush_sequence();
9368     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
9369     ok_sequence( WmEmptySeq, "no messages", FALSE );
9370     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
9371     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9372     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9373
9374     /* sent message with timeout */
9375     flush_sequence();
9376     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
9377     ok_sequence( WmEmptySeq, "no messages", FALSE );
9378     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
9379     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9380     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9381
9382     /* sent message with timeout and callback */
9383     flush_sequence();
9384     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
9385     ok_sequence( WmEmptySeq, "no messages", FALSE );
9386     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
9387     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9388     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9389
9390     /* sent message with callback */
9391     flush_sequence();
9392     SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
9393     ok_sequence( WmEmptySeq, "no messages", FALSE );
9394     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
9395     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9396     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9397
9398     /* direct window proc call */
9399     flush_sequence();
9400     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
9401     ok_sequence( WmEmptySeq, "no messages", FALSE );
9402     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
9403     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9404
9405     /* dispatch message */
9406     msg.hwnd = hwnd;
9407     msg.message = WM_CHAR;
9408     msg.wParam = dbch[0];
9409     msg.lParam = 0;
9410     DispatchMessageA( &msg );
9411     ok_sequence( WmEmptySeq, "no messages", FALSE );
9412     msg.wParam = dbch[1];
9413     DispatchMessageA( &msg );
9414     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9415
9416     /* window handle is irrelevant */
9417     flush_sequence();
9418     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
9419     ok_sequence( WmEmptySeq, "no messages", FALSE );
9420     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
9421     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9422     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9423
9424     /* interleaved post and send */
9425     flush_sequence();
9426     PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
9427     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
9428     ok_sequence( WmEmptySeq, "no messages", FALSE );
9429     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9430     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
9431     ok_sequence( WmEmptySeq, "no messages", FALSE );
9432     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
9433     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9434     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
9435     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9436     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
9437     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9438     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9439
9440     /* interleaved sent message and winproc */
9441     flush_sequence();
9442     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
9443     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
9444     ok_sequence( WmEmptySeq, "no messages", FALSE );
9445     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
9446     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9447     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
9448     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9449
9450     /* interleaved winproc and dispatch */
9451     msg.hwnd = hwnd;
9452     msg.message = WM_CHAR;
9453     msg.wParam = dbch[0];
9454     msg.lParam = 0;
9455     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
9456     DispatchMessageA( &msg );
9457     ok_sequence( WmEmptySeq, "no messages", FALSE );
9458     msg.wParam = dbch[1];
9459     DispatchMessageA( &msg );
9460     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9461     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
9462     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9463
9464     /* interleaved sends */
9465     flush_sequence();
9466     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
9467     SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
9468     ok_sequence( WmEmptySeq, "no messages", FALSE );
9469     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
9470     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9471     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
9472     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9473
9474     /* dbcs WM_CHAR */
9475     flush_sequence();
9476     SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
9477     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9478     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9479
9480     /* other char messages are not magic */
9481     PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
9482     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
9483     ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
9484     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
9485     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9486     PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
9487     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
9488     ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
9489     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
9490     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9491
9492     /* test retrieving messages */
9493
9494     PostMessageW( hwnd, WM_CHAR, wch, 0 );
9495     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
9496     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
9497     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9498     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
9499     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
9500     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
9501     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9502     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
9503     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9504
9505     /* message filters */
9506     PostMessageW( hwnd, WM_CHAR, wch, 0 );
9507     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
9508     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
9509     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9510     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
9511     /* message id is filtered, hwnd is not */
9512     ok( !PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ), "no message\n" );
9513     ok( PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE ), "no message\n" );
9514     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
9515     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9516     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
9517     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9518
9519     /* mixing GetMessage and PostMessage */
9520     PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
9521     ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
9522     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
9523     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9524     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
9525     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
9526     time = msg.time;
9527     pt = msg.pt;
9528     ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time );
9529     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
9530     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
9531     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9532     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
9533     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
9534     ok( msg.time == time, "bad time %x/%x\n", msg.time, time );
9535     ok( msg.pt.x == pt.x && msg.pt.y == pt.y, "bad point %u,%u/%u,%u\n", msg.pt.x, msg.pt.y, pt.x, pt.y );
9536     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9537
9538     /* without PM_REMOVE */
9539     PostMessageW( hwnd, WM_CHAR, wch, 0 );
9540     ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
9541     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
9542     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9543     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
9544     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
9545     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
9546     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9547     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
9548     ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
9549     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
9550     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9551     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
9552     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
9553     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
9554     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9555     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
9556     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9557
9558     DestroyWindow(hwnd);
9559 }
9560
9561 START_TEST(msg)
9562 {
9563     BOOL ret;
9564     FARPROC pIsWinEventHookInstalled = 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
9565
9566     init_procs();
9567
9568     if (!RegisterWindowClasses()) assert(0);
9569
9570     if (pSetWinEventHook)
9571     {
9572         hEvent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
9573                                                       GetModuleHandleA(0),
9574                                                       win_event_proc,
9575                                                       0,
9576                                                       GetCurrentThreadId(),
9577                                                       WINEVENT_INCONTEXT);
9578         assert(hEvent_hook);
9579
9580         if (pIsWinEventHookInstalled)
9581         {
9582             UINT event;
9583             for (event = EVENT_MIN; event <= EVENT_MAX; event++)
9584                 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
9585         }
9586     }
9587
9588     cbt_hook_thread_id = GetCurrentThreadId();
9589     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
9590     assert(hCBT_hook);
9591
9592     test_winevents();
9593
9594     /* Fix message sequences before removing 4 lines below */
9595 #if 1
9596     if (pUnhookWinEvent && hEvent_hook)
9597     {
9598         ret = pUnhookWinEvent(hEvent_hook);
9599         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
9600         pUnhookWinEvent = 0;
9601     }
9602     hEvent_hook = 0;
9603 #endif
9604
9605     test_ShowWindow();
9606     test_PeekMessage();
9607     test_scrollwindowex();
9608     test_messages();
9609     test_showwindow();
9610     invisible_parent_tests();
9611     test_mdi_messages();
9612     test_button_messages();
9613     test_static_messages();
9614     test_paint_messages();
9615     test_interthread_messages();
9616     test_message_conversion();
9617     test_accelerators();
9618     test_timers();
9619     test_set_hook();
9620     test_DestroyWindow();
9621     test_DispatchMessage();
9622     test_SendMessageTimeout();
9623     test_edit_messages();
9624     test_quit_message();
9625
9626     if (!pTrackMouseEvent)
9627         skip("TrackMouseEvent is not available\n");
9628     else
9629         test_TrackMouseEvent();
9630
9631     test_SetWindowRgn();
9632     test_sys_menu();
9633     test_dialog_messages();
9634     test_nullCallback();
9635     test_SetForegroundWindow();
9636     test_dbcs_wm_char();
9637
9638     UnhookWindowsHookEx(hCBT_hook);
9639     if (pUnhookWinEvent)
9640     {
9641         ret = pUnhookWinEvent(hEvent_hook);
9642         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
9643         SetLastError(0xdeadbeef);
9644         ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
9645         ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
9646            GetLastError() == 0xdeadbeef, /* Win9x */
9647            "unexpected error %d\n", GetLastError());
9648     }
9649     else
9650         skip("UnhookWinEvent is not available\n");
9651 }