user32/tests: Fix a number of message test failures on various Windows versions.
[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_KEYF1
47 #define WM_KEYF1 0x004d
48 #endif
49
50 #ifndef WM_SYSTIMER
51 #define WM_SYSTIMER         0x0118
52 #endif
53
54 #define WND_PARENT_ID           1
55 #define WND_POPUP_ID            2
56 #define WND_CHILD_ID            3
57
58 #ifndef WM_LBTRACKPOINT
59 #define WM_LBTRACKPOINT  0x0131
60 #endif
61
62 /* encoded DRAWITEMSTRUCT into an LPARAM */
63 typedef struct
64 {
65     union
66     {
67         struct
68         {
69             UINT type    : 4;  /* ODT_* flags */
70             UINT ctl_id  : 4;  /* Control ID */
71             UINT item_id : 4;  /* Menu item ID */
72             UINT action  : 4;  /* ODA_* flags */
73             UINT state   : 16; /* ODS_* flags */
74         } item;
75         LPARAM lp;
76     } u;
77 } DRAW_ITEM_STRUCT;
78
79 static BOOL test_DestroyWindow_flag;
80 static HWINEVENTHOOK hEvent_hook;
81
82 static void dump_winpos_flags(UINT flags);
83
84 static const WCHAR testWindowClassW[] =
85 { 'T','e','s','t','W','i','n','d','o','w','C','l','a','s','s','W',0 };
86
87 /*
88 FIXME: add tests for these
89 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
90  WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
91  WS_THICKFRAME: thick border
92  WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
93  WS_BORDER (default for overlapped windows): single black border
94  none (default for child (and popup?) windows): no border
95 */
96
97 typedef enum {
98     sent=0x1,
99     posted=0x2,
100     parent=0x4,
101     wparam=0x8,
102     lparam=0x10,
103     defwinproc=0x20,
104     beginpaint=0x40,
105     optional=0x80,
106     hook=0x100,
107     winevent_hook=0x200
108 } msg_flags_t;
109
110 struct message {
111     UINT message;          /* the WM_* code */
112     msg_flags_t flags;     /* message props */
113     WPARAM wParam;         /* expected value of wParam */
114     LPARAM lParam;         /* expected value of lParam */
115 };
116
117 /* Empty message sequence */
118 static const struct message WmEmptySeq[] =
119 {
120     { 0 }
121 };
122 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
123 static const struct message WmCreateOverlappedSeq[] = {
124     { HCBT_CREATEWND, hook },
125     { WM_GETMINMAXINFO, sent },
126     { WM_NCCREATE, sent },
127     { WM_NCCALCSIZE, sent|wparam, 0 },
128     { 0x0093, sent|defwinproc|optional },
129     { 0x0094, sent|defwinproc|optional },
130     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
131     { WM_CREATE, sent },
132     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
133     { 0 }
134 };
135 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
136  * for a not visible overlapped window.
137  */
138 static const struct message WmSWP_ShowOverlappedSeq[] = {
139     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
140     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
141     { WM_NCPAINT, sent|wparam|optional, 1 },
142     { WM_GETTEXT, sent|defwinproc|optional },
143     { WM_ERASEBKGND, sent|optional },
144     { HCBT_ACTIVATE, hook },
145     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
146     { WM_NOTIFYFORMAT, sent|optional },
147     { WM_QUERYUISTATE, sent|optional },
148     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
149     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
150     { WM_ACTIVATEAPP, sent|wparam, 1 },
151     { WM_NCACTIVATE, sent|wparam, 1 },
152     { WM_GETTEXT, sent|defwinproc|optional },
153     { WM_ACTIVATE, sent|wparam, 1 },
154     { HCBT_SETFOCUS, hook },
155     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
156     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
157     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
158     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
159     { WM_NCPAINT, sent|wparam|optional, 1 },
160     { WM_GETTEXT, sent|defwinproc|optional },
161     { WM_ERASEBKGND, sent|optional },
162     /* Win9x adds SWP_NOZORDER below */
163     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
164     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
165     { WM_NCPAINT, sent|wparam|optional, 1 },
166     { WM_ERASEBKGND, sent|optional },
167     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
168     { WM_PAINT, sent|optional },
169     { WM_NCPAINT, sent|beginpaint|optional },
170     { WM_ERASEBKGND, sent|beginpaint|optional },
171     { 0 }
172 };
173 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
174  * for a visible overlapped window.
175  */
176 static const struct message WmSWP_HideOverlappedSeq[] = {
177     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
178     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
179     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
180     { 0 }
181 };
182
183 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
184  * for a visible overlapped window.
185  */
186 static const struct message WmSWP_ResizeSeq[] = {
187     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
188     { WM_GETMINMAXINFO, sent|defwinproc },
189     { WM_NCCALCSIZE, sent|wparam, TRUE },
190     { WM_NCPAINT, sent|optional },
191     { WM_GETTEXT, sent|defwinproc|optional },
192     { WM_ERASEBKGND, sent|optional },
193     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
194     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
195     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
196     { WM_NCPAINT, sent|optional },
197     { WM_GETTEXT, sent|defwinproc|optional },
198     { WM_ERASEBKGND, sent|optional },
199     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
200     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
201     { 0 }
202 };
203
204 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
205  * for a visible popup window.
206  */
207 static const struct message WmSWP_ResizePopupSeq[] = {
208     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
209     { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* Win9x */
210     { WM_NCCALCSIZE, sent|wparam, TRUE },
211     { WM_NCPAINT, sent|optional },
212     { WM_GETTEXT, sent|defwinproc|optional },
213     { WM_ERASEBKGND, sent|optional },
214     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
215     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
216     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
217     { WM_NCPAINT, sent|optional },
218     { WM_GETTEXT, sent|defwinproc|optional },
219     { WM_ERASEBKGND, sent|optional },
220     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
221     { 0 }
222 };
223
224 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE)
225  * for a visible overlapped window.
226  */
227 static const struct message WmSWP_MoveSeq[] = {
228     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE },
229     { WM_NCPAINT, sent|optional },
230     { WM_GETTEXT, sent|defwinproc|optional },
231     { WM_ERASEBKGND, sent|optional },
232     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
233     { WM_MOVE, sent|defwinproc|wparam, 0 },
234     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
235     { 0 }
236 };
237 /* Resize with SetWindowPos(SWP_NOZORDER)
238  * for a visible overlapped window
239  * SWP_NOZORDER is stripped by the logging code
240  */
241 static const struct message WmSWP_ResizeNoZOrder[] = {
242     { WM_WINDOWPOSCHANGING, sent|wparam, /*SWP_NOZORDER|*/SWP_NOACTIVATE },
243     { WM_GETMINMAXINFO, sent|defwinproc },
244     { WM_NCCALCSIZE, sent|wparam, 1 },
245     { WM_NCPAINT, sent },
246     { WM_GETTEXT, sent|defwinproc|optional },
247     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
248     { WM_WINDOWPOSCHANGED, sent|wparam, /*SWP_NOZORDER|*/SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE },
249     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
250     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
251     { WM_NCPAINT, sent|optional }, /* Win9x doesn't send it */
252     { WM_GETTEXT, sent|defwinproc|optional }, /* Win9x doesn't send it */
253     { WM_ERASEBKGND, sent|optional }, /* Win9x doesn't send it */
254     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
255     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
256     { 0 }
257 };
258
259 /* Switch visible mdi children */
260 static const struct message WmSwitchChild[] = {
261     /* Switch MDI child */
262     { WM_MDIACTIVATE, sent },/* in the MDI client */
263     { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 1st MDI child */
264     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
265     { WM_CHILDACTIVATE, sent },/* in the 1st MDI child */
266     /* Deactivate 2nd MDI child */
267     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
268     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
269     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
270     /* Preparing for maximize and maximaze the 1st MDI child */
271     { WM_GETMINMAXINFO, sent|defwinproc }, /* in the 1st MDI child */
272     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED }, /* in the 1st MDI child */
273     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
274     { WM_CHILDACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
275     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 1st MDI child */
276     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, /* in the 1st MDI child */
277     /* Lock redraw 2nd MDI child */
278     { WM_SETREDRAW, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
279     { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
280     /* Restore 2nd MDI child */
281     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },/* in the 2nd MDI child */
282     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
283     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
284     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 2nd MDI child */
285     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, /* in the 2nd MDI child */
286     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
287     /* Redraw 2nd MDI child */
288     { WM_SETREDRAW, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
289     /* Redraw MDI frame */
290     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },/* in MDI frame */
291     { WM_NCCALCSIZE, sent|wparam, 1 },/* in MDI frame */
292     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in MDI frame */
293     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in MDI frame */
294     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
295     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
296     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
297     { HCBT_SETFOCUS, hook },
298     { WM_KILLFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
299     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },/* in the 1st MDI child */
300     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
301     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
302     { WM_SETFOCUS, sent },/* in the MDI client */
303     { HCBT_SETFOCUS, hook },
304     { WM_KILLFOCUS, sent },/* in the MDI client */
305     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
306     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, /* in the 1st MDI child */
307     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
308     { WM_SETFOCUS, sent|defwinproc }, /* in the 1st MDI child */
309     { WM_MDIACTIVATE, sent|defwinproc },/* in the 1st MDI child */
310     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* in the 1st MDI child */
311     { 0 }
312 };
313
314 /* Switch visible not maximized mdi children */
315 static const struct message WmSwitchNotMaximizedChild[] = {
316     /* Switch not maximized MDI child */
317     { WM_MDIACTIVATE, sent },/* in the MDI client */
318     { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 2nd MDI child */
319     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
320     { WM_CHILDACTIVATE, sent },/* in the 2nd MDI child */
321     /* Deactivate 1st MDI child */
322     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
323     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
324     /* Activate 2nd MDI child */
325     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE}, /* in the 2nd MDI child */
326     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 2nd MDI child */
327     { HCBT_SETFOCUS, hook }, /* in the 1st MDI child */
328     { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
329     { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
330     { WM_IME_SETCONTEXT, sent|optional }, /* in the  MDI client */
331     { WM_SETFOCUS, sent, 0 }, /* in the  MDI client */
332     { HCBT_SETFOCUS, hook },
333     { WM_KILLFOCUS, sent }, /* in the  MDI client */
334     { WM_IME_SETCONTEXT, sent|optional }, /* in the  MDI client */
335     { WM_IME_SETCONTEXT, sent|defwinproc|optional  }, /* in the 1st MDI child */
336     { WM_SETFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
337     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
338     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in the 2nd MDI child */
339     { 0 }
340 };
341
342
343 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
344                 SWP_NOZORDER|SWP_FRAMECHANGED)
345  * for a visible overlapped window with WS_CLIPCHILDREN style set.
346  */
347 static const struct message WmSWP_FrameChanged_clip[] = {
348     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
349     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
350     { WM_NCPAINT, sent|parent }, /* wparam != 1 */
351     { WM_GETTEXT, sent|parent|defwinproc|optional },
352     { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
353     { WM_NCPAINT, sent }, /* wparam != 1 */
354     { WM_ERASEBKGND, sent },
355     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
356     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
357     { WM_PAINT, sent },
358     { 0 }
359 };
360 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|
361                 SWP_NOZORDER|SWP_FRAMECHANGED)
362  * for a visible overlapped window.
363  */
364 static const struct message WmSWP_FrameChangedDeferErase[] = {
365     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
366     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
367     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
368     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
369     { WM_PAINT, sent|parent },
370     { WM_NCPAINT, sent|beginpaint|parent }, /* wparam != 1 */
371     { WM_GETTEXT, sent|beginpaint|parent|defwinproc|optional },
372     { WM_PAINT, sent },
373     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
374     { WM_ERASEBKGND, sent|beginpaint },
375     { 0 }
376 };
377
378 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
379                 SWP_NOZORDER|SWP_FRAMECHANGED)
380  * for a visible overlapped window without WS_CLIPCHILDREN style set.
381  */
382 static const struct message WmSWP_FrameChanged_noclip[] = {
383     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
384     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
385     { WM_NCPAINT, sent|parent }, /* wparam != 1 */
386     { WM_GETTEXT, sent|parent|defwinproc|optional },
387     { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
388     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
389     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
390     { WM_PAINT, sent },
391     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
392     { WM_ERASEBKGND, sent|beginpaint },
393     { 0 }
394 };
395
396 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
397 static const struct message WmShowOverlappedSeq[] = {
398     { WM_SHOWWINDOW, sent|wparam, 1 },
399     { WM_NCPAINT, sent|wparam|optional, 1 },
400     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
401     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
402     { WM_NCPAINT, sent|wparam|optional, 1 },
403     { WM_GETTEXT, sent|defwinproc|optional },
404     { WM_ERASEBKGND, sent|optional },
405     { HCBT_ACTIVATE, hook },
406     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
407     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
408     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
409     { WM_NCPAINT, sent|wparam|optional, 1 },
410     { WM_ACTIVATEAPP, sent|wparam, 1 },
411     { WM_NCACTIVATE, sent|wparam, 1 },
412     { WM_GETTEXT, sent|defwinproc|optional },
413     { WM_ACTIVATE, sent|wparam, 1 },
414     { HCBT_SETFOCUS, hook },
415     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
416     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
417     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
418     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
419     { WM_NCPAINT, sent|wparam|optional, 1 },
420     { WM_GETTEXT, sent|defwinproc|optional },
421     { WM_ERASEBKGND, sent|optional },
422     /* Win9x adds SWP_NOZORDER below */
423     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
424     { WM_NCCALCSIZE, sent|optional },
425     { WM_NCPAINT, sent|optional },
426     { WM_ERASEBKGND, sent|optional },
427 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
428        * messages. Does that mean that CreateWindow doesn't set initial
429        * window dimensions for overlapped windows?
430        */
431     { WM_SIZE, sent },
432     { WM_MOVE, sent },
433 #endif
434     { WM_PAINT, sent|optional },
435     { WM_NCPAINT, sent|beginpaint|optional },
436     { 0 }
437 };
438 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible overlapped window */
439 static const struct message WmShowMaxOverlappedSeq[] = {
440     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
441     { WM_GETMINMAXINFO, sent },
442     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
443     { WM_GETMINMAXINFO, sent|defwinproc },
444     { WM_NCCALCSIZE, sent|wparam, TRUE },
445     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
446     { HCBT_ACTIVATE, hook },
447     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
448     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
449     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
450     { WM_ACTIVATEAPP, sent|wparam, 1 },
451     { WM_NCACTIVATE, sent|wparam, 1 },
452     { WM_GETTEXT, sent|defwinproc|optional },
453     { WM_ACTIVATE, sent|wparam, 1 },
454     { HCBT_SETFOCUS, hook },
455     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
456     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
457     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
458     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
459     { WM_NCPAINT, sent|wparam|optional, 1 },
460     { WM_GETTEXT, sent|defwinproc|optional },
461     { WM_ERASEBKGND, sent|optional },
462     /* Win9x adds SWP_NOZORDER below */
463     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
464     { WM_MOVE, sent|defwinproc },
465     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
466     { WM_NCCALCSIZE, sent|optional },
467     { WM_NCPAINT, sent|optional },
468     { WM_ERASEBKGND, sent|optional },
469     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
470     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
471     { WM_PAINT, sent|optional },
472     { WM_NCPAINT, sent|beginpaint|optional },
473     { WM_ERASEBKGND, sent|beginpaint|optional },
474     { 0 }
475 };
476 /* ShowWindow(SW_RESTORE) for a not visible maximized overlapped window */
477 static const struct message WmShowRestoreMaxOverlappedSeq[] = {
478     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
479     { WM_GETTEXT, sent|optional },
480     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
481     { WM_GETMINMAXINFO, sent|defwinproc },
482     { WM_NCCALCSIZE, sent|wparam, TRUE },
483     { WM_NCPAINT, sent|optional },
484     { WM_GETTEXT, sent|defwinproc|optional },
485     { WM_ERASEBKGND, sent|optional },
486     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
487     { WM_MOVE, sent|defwinproc|optional },
488     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
489     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
490     { WM_NCPAINT, sent|optional },
491     { WM_ERASEBKGND, sent|optional },
492     { WM_PAINT, sent|optional },
493     { WM_NCPAINT, sent|beginpaint|optional },
494     { WM_ERASEBKGND, sent|beginpaint|optional },
495     { 0 }
496 };
497 /* ShowWindow(SW_RESTORE) for a not visible minimized overlapped window */
498 static const struct message WmShowRestoreMinOverlappedSeq[] = {
499     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
500     { WM_QUERYOPEN, sent|optional },
501     { WM_GETTEXT, sent|optional },
502     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED|SWP_NOCOPYBITS },
503     { WM_GETMINMAXINFO, sent|defwinproc },
504     { WM_NCCALCSIZE, sent|wparam, TRUE },
505     { HCBT_ACTIVATE, hook },
506     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
507     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
508     { WM_ACTIVATEAPP, sent|wparam, 1 },
509     { WM_NCACTIVATE, sent|wparam, 1 },
510     { WM_GETTEXT, sent|defwinproc|optional },
511     { WM_ACTIVATE, sent|wparam, 1 },
512     { HCBT_SETFOCUS, hook },
513     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
514     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
515     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
516     { WM_NCPAINT, sent|wparam|optional, 1 },
517     { WM_GETTEXT, sent|defwinproc|optional },
518     { WM_ERASEBKGND, sent },
519     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_STATECHANGED|SWP_FRAMECHANGED|SWP_NOCOPYBITS },
520     { WM_MOVE, sent|defwinproc },
521     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
522     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
523     { WM_NCPAINT, sent|wparam|optional, 1 },
524     { WM_ERASEBKGND, sent|optional },
525     { WM_ACTIVATE, sent|wparam, 1 },
526     { WM_PAINT, sent|optional },
527     { WM_NCPAINT, sent|beginpaint|optional },
528     { WM_ERASEBKGND, sent|beginpaint|optional },
529     { 0 }
530 };
531 /* ShowWindow(SW_SHOWMINIMIZED) for a not visible overlapped window */
532 static const struct message WmShowMinOverlappedSeq[] = {
533     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
534     { HCBT_SETFOCUS, hook },
535     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
536     { WM_KILLFOCUS, sent },
537     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
538     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
539     { WM_GETTEXT, sent|optional },
540     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCOPYBITS|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
541     { WM_GETMINMAXINFO, sent|defwinproc },
542     { WM_NCCALCSIZE, sent|wparam, TRUE },
543     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
544     { WM_NCPAINT, sent|optional },
545     { WM_GETTEXT, sent|defwinproc|optional },
546     { WM_WINDOWPOSCHANGED, sent },
547     { WM_MOVE, sent|defwinproc },
548     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
549     { WM_NCCALCSIZE, sent|optional },
550     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
551     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
552     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
553     { WM_NCACTIVATE, sent|wparam, 0 },
554     { WM_GETTEXT, sent|defwinproc|optional },
555     { WM_ACTIVATE, sent },
556     { WM_ACTIVATEAPP, sent|wparam, 0 },
557     { WM_PAINT, sent|optional },
558     { WM_NCPAINT, sent|beginpaint|optional },
559     { WM_ERASEBKGND, sent|beginpaint|optional },
560     { 0 }
561 };
562 /* ShowWindow(SW_HIDE) for a visible overlapped window */
563 static const struct message WmHideOverlappedSeq[] = {
564     { WM_SHOWWINDOW, sent|wparam, 0 },
565     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
566     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
567     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
568     { WM_SIZE, sent|optional }, /* XP doesn't send it */
569     { WM_MOVE, sent|optional }, /* XP doesn't send it */
570     { WM_NCACTIVATE, sent|wparam, 0 },
571     { WM_ACTIVATE, sent|wparam, 0 },
572     { WM_ACTIVATEAPP, sent|wparam, 0 },
573     { WM_KILLFOCUS, sent|wparam, 0 },
574     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
575     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
576     { 0 }
577 };
578 /* DestroyWindow for a visible overlapped window */
579 static const struct message WmDestroyOverlappedSeq[] = {
580     { HCBT_DESTROYWND, hook },
581     { 0x0090, sent|optional },
582     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
583     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
584     { 0x0090, sent|optional },
585     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
586     { WM_NCACTIVATE, sent|optional|wparam, 0 },
587     { WM_ACTIVATE, sent|optional|wparam, 0 },
588     { WM_ACTIVATEAPP, sent|optional|wparam, 0 },
589     { WM_KILLFOCUS, sent|optional|wparam, 0 },
590     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
591     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
592     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
593     { WM_DESTROY, sent },
594     { WM_NCDESTROY, sent },
595     { 0 }
596 };
597 /* CreateWindow(WS_MAXIMIZE|WS_VISIBLE) for popup window */
598 static const struct message WmCreateMaxPopupSeq[] = {
599     { HCBT_CREATEWND, hook },
600     { WM_NCCREATE, sent },
601     { WM_NCCALCSIZE, sent|wparam, 0 },
602     { WM_CREATE, sent },
603     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
604     { WM_SIZE, sent|wparam, SIZE_RESTORED },
605     { WM_MOVE, sent },
606     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
607     { WM_GETMINMAXINFO, sent },
608     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
609     { WM_NCCALCSIZE, sent|wparam, TRUE },
610     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
611     { WM_MOVE, sent|defwinproc },
612     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
613     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
614     { WM_SHOWWINDOW, sent|wparam, 1 },
615     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
616     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
617     { HCBT_ACTIVATE, hook },
618     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
619     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
620     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
621     { WM_ACTIVATEAPP, sent|wparam, 1 },
622     { WM_NCACTIVATE, sent|wparam, 1 },
623     { WM_ACTIVATE, sent|wparam, 1 },
624     { HCBT_SETFOCUS, hook },
625     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
626     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
627     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
628     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
629     { WM_SYNCPAINT, sent|wparam|optional, 4 },
630     { WM_NCPAINT, sent|wparam|optional, 1 },
631     { WM_ERASEBKGND, sent|optional },
632     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
633     { 0 }
634 };
635 /* CreateWindow(WS_MAXIMIZE) for popup window, not initially visible */
636 static const struct message WmCreateInvisibleMaxPopupSeq[] = {
637     { HCBT_CREATEWND, hook },
638     { WM_NCCREATE, sent },
639     { WM_NCCALCSIZE, sent|wparam, 0 },
640     { WM_CREATE, sent },
641     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
642     { WM_SIZE, sent|wparam, SIZE_RESTORED },
643     { WM_MOVE, sent },
644     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
645     { WM_GETMINMAXINFO, sent },
646     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED  },
647     { WM_NCCALCSIZE, sent|wparam, TRUE },
648     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
649     { WM_MOVE, sent|defwinproc },
650     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
651     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
652     { 0 }
653 };
654 /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */
655 static const struct message WmShowMaxPopupResizedSeq[] = {
656     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
657     { WM_GETMINMAXINFO, sent },
658     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
659     { WM_NCCALCSIZE, sent|wparam, TRUE },
660     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
661     { HCBT_ACTIVATE, hook },
662     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
663     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
664     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
665     { WM_ACTIVATEAPP, sent|wparam, 1 },
666     { WM_NCACTIVATE, sent|wparam, 1 },
667     { WM_ACTIVATE, sent|wparam, 1 },
668     { HCBT_SETFOCUS, hook },
669     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
670     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
671     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
672     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
673     { WM_NCPAINT, sent|wparam|optional, 1 },
674     { WM_ERASEBKGND, sent|optional },
675     { WM_WINDOWPOSCHANGED, sent },
676     /* WinNT4.0 sends WM_MOVE */
677     { WM_MOVE, sent|defwinproc|optional },
678     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
679     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
680     { 0 }
681 };
682 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible popup window */
683 static const struct message WmShowMaxPopupSeq[] = {
684     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
685     { WM_GETMINMAXINFO, sent },
686     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
687     { WM_NCCALCSIZE, sent|wparam, TRUE },
688     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
689     { HCBT_ACTIVATE, hook },
690     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
691     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
692     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
693     { WM_ACTIVATEAPP, sent|wparam, 1 },
694     { WM_NCACTIVATE, sent|wparam, 1 },
695     { WM_ACTIVATE, sent|wparam, 1 },
696     { HCBT_SETFOCUS, hook },
697     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
698     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
699     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
700     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
701     { WM_SYNCPAINT, sent|wparam|optional, 4 },
702     { WM_NCPAINT, sent|wparam|optional, 1 },
703     { WM_ERASEBKGND, sent|optional },
704     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE },
705     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
706     { 0 }
707 };
708 /* CreateWindow(WS_VISIBLE) for popup window */
709 static const struct message WmCreatePopupSeq[] = {
710     { HCBT_CREATEWND, hook },
711     { WM_NCCREATE, sent },
712     { WM_NCCALCSIZE, sent|wparam, 0 },
713     { WM_CREATE, sent },
714     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
715     { WM_SIZE, sent|wparam, SIZE_RESTORED },
716     { WM_MOVE, sent },
717     { WM_SHOWWINDOW, sent|wparam, 1 },
718     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
719     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
720     { HCBT_ACTIVATE, hook },
721     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
722     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
723     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
724     { WM_NCPAINT, sent|wparam|optional, 1 },
725     { WM_ERASEBKGND, sent|optional },
726     { WM_ACTIVATEAPP, sent|wparam, 1 },
727     { WM_NCACTIVATE, sent|wparam, 1 },
728     { WM_ACTIVATE, sent|wparam, 1 },
729     { HCBT_SETFOCUS, hook },
730     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
731     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
732     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
733     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
734     { WM_SYNCPAINT, sent|wparam|optional, 4 },
735     { WM_NCPAINT, sent|wparam|optional, 1 },
736     { WM_ERASEBKGND, sent|optional },
737     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
738     { 0 }
739 };
740 /* ShowWindow(SW_SHOWMAXIMIZED) for a visible popup window */
741 static const struct message WmShowVisMaxPopupSeq[] = {
742     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
743     { WM_GETMINMAXINFO, sent },
744     { WM_GETTEXT, sent|optional },
745     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
746     { WM_NCCALCSIZE, sent|wparam, TRUE },
747     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
748     { WM_NCPAINT, sent|wparam|optional, 1 },
749     { WM_ERASEBKGND, sent|optional },
750     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
751     { WM_MOVE, sent|defwinproc },
752     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
753     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
754     { 0 }
755 };
756 /* CreateWindow (for a child popup window, not initially visible) */
757 static const struct message WmCreateChildPopupSeq[] = {
758     { HCBT_CREATEWND, hook },
759     { WM_NCCREATE, sent }, 
760     { WM_NCCALCSIZE, sent|wparam, 0 },
761     { WM_CREATE, sent },
762     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
763     { WM_SIZE, sent|wparam, SIZE_RESTORED },
764     { WM_MOVE, sent },
765     { 0 }
766 };
767 /* CreateWindow (for a popup window, not initially visible,
768  * which sets WS_VISIBLE in WM_CREATE handler)
769  */
770 static const struct message WmCreateInvisiblePopupSeq[] = {
771     { HCBT_CREATEWND, hook },
772     { WM_NCCREATE, sent }, 
773     { WM_NCCALCSIZE, sent|wparam, 0 },
774     { WM_CREATE, sent },
775     { WM_STYLECHANGING, sent },
776     { WM_STYLECHANGED, sent },
777     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
778     { WM_SIZE, sent|wparam, SIZE_RESTORED },
779     { WM_MOVE, sent },
780     { 0 }
781 };
782 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
783  * for a popup window with WS_VISIBLE style set
784  */
785 static const struct message WmShowVisiblePopupSeq_2[] = {
786     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
787     { 0 }
788 };
789 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
790  * for a popup window with WS_VISIBLE style set
791  */
792 static const struct message WmShowVisiblePopupSeq_3[] = {
793     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
794     { HCBT_ACTIVATE, hook },
795     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
796     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
797     { WM_WINDOWPOSCHANGING, sent|wparam|optional, 0 },
798     { WM_NCACTIVATE, sent|wparam, 1 },
799     { WM_ACTIVATE, sent|wparam, 1 },
800     { HCBT_SETFOCUS, hook },
801     { WM_KILLFOCUS, sent|parent },
802     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
803     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
804     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
805     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
806     { WM_SETFOCUS, sent|defwinproc },
807     { 0 }
808 };
809 /* CreateWindow (for child window, not initially visible) */
810 static const struct message WmCreateChildSeq[] = {
811     { HCBT_CREATEWND, hook },
812     { WM_NCCREATE, sent }, 
813     /* child is inserted into parent's child list after WM_NCCREATE returns */
814     { WM_NCCALCSIZE, sent|wparam, 0 },
815     { WM_CREATE, sent },
816     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
817     { WM_SIZE, sent|wparam, SIZE_RESTORED },
818     { WM_MOVE, sent },
819     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
820     { 0 }
821 };
822 /* CreateWindow (for maximized child window, not initially visible) */
823 static const struct message WmCreateMaximizedChildSeq[] = {
824     { HCBT_CREATEWND, hook },
825     { WM_NCCREATE, sent }, 
826     { WM_NCCALCSIZE, sent|wparam, 0 },
827     { WM_CREATE, sent },
828     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
829     { WM_SIZE, sent|wparam, SIZE_RESTORED },
830     { WM_MOVE, sent },
831     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
832     { WM_GETMINMAXINFO, sent },
833     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
834     { WM_NCCALCSIZE, sent|wparam, 1 },
835     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
836     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
837     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
838     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
839     { 0 }
840 };
841 /* CreateWindow (for a child window, initially visible) */
842 static const struct message WmCreateVisibleChildSeq[] = {
843     { HCBT_CREATEWND, hook },
844     { WM_NCCREATE, sent }, 
845     /* child is inserted into parent's child list after WM_NCCREATE returns */
846     { WM_NCCALCSIZE, sent|wparam, 0 },
847     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
848     { WM_CREATE, sent },
849     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
850     { WM_SIZE, sent|wparam, SIZE_RESTORED },
851     { WM_MOVE, sent },
852     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
853     { WM_SHOWWINDOW, sent|wparam, 1 },
854     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
855     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
856     { WM_ERASEBKGND, sent|parent|optional },
857     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
858     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */
859     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
860     { 0 }
861 };
862 /* ShowWindow(SW_SHOW) for a not visible child window */
863 static const struct message WmShowChildSeq[] = {
864     { WM_SHOWWINDOW, sent|wparam, 1 },
865     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
866     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
867     { WM_ERASEBKGND, sent|parent|optional },
868     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
869     { 0 }
870 };
871 /* ShowWindow(SW_HIDE) for a visible child window */
872 static const struct message WmHideChildSeq[] = {
873     { WM_SHOWWINDOW, sent|wparam, 0 },
874     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
875     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
876     { WM_ERASEBKGND, sent|parent|optional },
877     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
878     { 0 }
879 };
880 /* ShowWindow(SW_HIDE) for a visible child window checking all parent events*/
881 static const struct message WmHideChildSeq2[] = {
882     { WM_SHOWWINDOW, sent|wparam, 0 },
883     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
884     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
885     { WM_ERASEBKGND, sent|parent },
886     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
887     { 0 }
888 };
889 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
890  * for a not visible child window
891  */
892 static const struct message WmShowChildSeq_2[] = {
893     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
894     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
895     { WM_CHILDACTIVATE, sent },
896     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
897     { 0 }
898 };
899 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
900  * for a not visible child window
901  */
902 static const struct message WmShowChildSeq_3[] = {
903     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
904     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
905     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
906     { 0 }
907 };
908 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
909  * for a visible child window with a caption
910  */
911 static const struct message WmShowChildSeq_4[] = {
912     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
913     { WM_CHILDACTIVATE, sent },
914     { 0 }
915 };
916 /* ShowWindow(SW_MINIMIZE) for child with invisible parent */
917 static const struct message WmShowChildInvisibleParentSeq_1[] = {
918     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
919     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
920     { WM_NCCALCSIZE, sent|wparam, 1 },
921     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
922     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
923     { WM_MOVE, sent|defwinproc },
924     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
925     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
926     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
927     /* FIXME: Wine creates an icon/title window while Windows doesn't */
928     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
929     { WM_GETTEXT, sent|optional },
930     { 0 }
931 };
932 /* repeated ShowWindow(SW_MINIMIZE) for child with invisible parent */
933 static const struct message WmShowChildInvisibleParentSeq_1r[] = {
934     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
935     { 0 }
936 };
937 /* ShowWindow(SW_MAXIMIZE) for child with invisible parent */
938 static const struct message WmShowChildInvisibleParentSeq_2[] = {
939     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
940     { WM_GETMINMAXINFO, sent },
941     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
942     { WM_NCCALCSIZE, sent|wparam, 1 },
943     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
944     { WM_CHILDACTIVATE, sent },
945     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
946     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
947     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
948     { 0 }
949 };
950 /* repeated ShowWindow(SW_MAXIMIZE) for child with invisible parent */
951 static const struct message WmShowChildInvisibleParentSeq_2r[] = {
952     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
953     { 0 }
954 };
955 /* ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
956 static const struct message WmShowChildInvisibleParentSeq_3[] = {
957     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
958     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
959     { WM_NCCALCSIZE, sent|wparam, 1 },
960     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
961     { WM_CHILDACTIVATE, sent },
962     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
963     { WM_MOVE, sent|defwinproc },
964     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
965     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
966     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
967     /* FIXME: Wine creates an icon/title window while Windows doesn't */
968     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
969     { WM_GETTEXT, sent|optional },
970     { 0 }
971 };
972 /* repeated ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
973 static const struct message WmShowChildInvisibleParentSeq_3r[] = {
974     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
975     { 0 }
976 };
977 /* ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
978 static const struct message WmShowChildInvisibleParentSeq_4[] = {
979     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
980     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
981     { WM_NCCALCSIZE, sent|wparam, 1 },
982     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
983     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
984     { WM_MOVE, sent|defwinproc },
985     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
986     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
987     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
988     /* FIXME: Wine creates an icon/title window while Windows doesn't */
989     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
990     { WM_GETTEXT, sent|optional },
991     { 0 }
992 };
993 /* repeated ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
994 static const struct message WmShowChildInvisibleParentSeq_4r[] = {
995     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
996     { 0 }
997 };
998 /* ShowWindow(SW_SHOW) for child with invisible parent */
999 static const struct message WmShowChildInvisibleParentSeq_5[] = {
1000     { WM_SHOWWINDOW, sent|wparam, 1 },
1001     { 0 }
1002 };
1003 /* ShowWindow(SW_HIDE) for child with invisible parent */
1004 static const struct message WmHideChildInvisibleParentSeq[] = {
1005     { WM_SHOWWINDOW, sent|wparam, 0 },
1006     { 0 }
1007 };
1008 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
1009 static const struct message WmShowChildInvisibleParentSeq_6[] = {
1010     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1011     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1012     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1013     { 0 }
1014 };
1015 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
1016 static const struct message WmHideChildInvisibleParentSeq_2[] = {
1017     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1018     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1019     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1020     { 0 }
1021 };
1022 /* DestroyWindow for a visible child window */
1023 static const struct message WmDestroyChildSeq[] = {
1024     { HCBT_DESTROYWND, hook },
1025     { 0x0090, sent|optional },
1026     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1027     { WM_SHOWWINDOW, sent|wparam, 0 },
1028     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1029     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1030     { WM_ERASEBKGND, sent|parent|optional },
1031     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1032     { HCBT_SETFOCUS, hook }, /* set focus to a parent */
1033     { WM_KILLFOCUS, sent },
1034     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1035     { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
1036     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1037     { WM_SETFOCUS, sent|parent },
1038     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1039     { WM_DESTROY, sent },
1040     { WM_DESTROY, sent|optional }, /* some other (IME?) window */
1041     { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
1042     { WM_NCDESTROY, sent },
1043     { 0 }
1044 };
1045 /* DestroyWindow for a visible child window with invisible parent */
1046 static const struct message WmDestroyInvisibleChildSeq[] = {
1047     { HCBT_DESTROYWND, hook },
1048     { 0x0090, sent|optional },
1049     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1050     { WM_SHOWWINDOW, sent|wparam, 0 },
1051     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1052     { WM_DESTROY, sent },
1053     { WM_NCDESTROY, sent },
1054     { 0 }
1055 };
1056 /* Moving the mouse in nonclient area */
1057 static const struct message WmMouseMoveInNonClientAreaSeq[] = { /* FIXME: add */
1058     { WM_NCHITTEST, sent },
1059     { WM_SETCURSOR, sent },
1060     { WM_NCMOUSEMOVE, posted },
1061     { 0 }
1062 };
1063 /* Moving the mouse in client area */
1064 static const struct message WmMouseMoveInClientAreaSeq[] = { /* FIXME: add */
1065     { WM_NCHITTEST, sent },
1066     { WM_SETCURSOR, sent },
1067     { WM_MOUSEMOVE, posted },
1068     { 0 }
1069 };
1070 /* Moving by dragging the title bar (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
1071 static const struct message WmDragTitleBarSeq[] = { /* FIXME: add */
1072     { WM_NCLBUTTONDOWN, sent|wparam, HTCAPTION },
1073     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_MOVE+2 },
1074     { WM_GETMINMAXINFO, sent|defwinproc },
1075     { WM_ENTERSIZEMOVE, sent|defwinproc },
1076     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
1077     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
1078     { WM_MOVE, sent|defwinproc },
1079     { WM_EXITSIZEMOVE, sent|defwinproc },
1080     { 0 }
1081 };
1082 /* Sizing by dragging the thick borders (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
1083 static const struct message WmDragThickBordersBarSeq[] = { /* FIXME: add */
1084     { WM_NCLBUTTONDOWN, sent|wparam, 0xd },
1085     { WM_SYSCOMMAND, sent|defwinproc|wparam, 0xf004 },
1086     { WM_GETMINMAXINFO, sent|defwinproc },
1087     { WM_ENTERSIZEMOVE, sent|defwinproc },
1088     { WM_SIZING, sent|defwinproc|wparam, 4}, /* one for each mouse movement */
1089     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
1090     { WM_GETMINMAXINFO, sent|defwinproc },
1091     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
1092     { WM_NCPAINT, sent|defwinproc|wparam, 1 },
1093     { WM_GETTEXT, sent|defwinproc },
1094     { WM_ERASEBKGND, sent|defwinproc },
1095     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
1096     { WM_MOVE, sent|defwinproc },
1097     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1098     { WM_EXITSIZEMOVE, sent|defwinproc },
1099     { 0 }
1100 };
1101 /* Resizing child window with MoveWindow (32) */
1102 static const struct message WmResizingChildWithMoveWindowSeq[] = {
1103     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
1104     { WM_NCCALCSIZE, sent|wparam, 1 },
1105     { WM_ERASEBKGND, sent|parent|optional },
1106     { WM_ERASEBKGND, sent|optional },
1107     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE },
1108     { WM_MOVE, sent|defwinproc },
1109     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1110     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1111     { 0 }
1112 };
1113 /* Clicking on inactive button */
1114 static const struct message WmClickInactiveButtonSeq[] = { /* FIXME: add */
1115     { WM_NCHITTEST, sent },
1116     { WM_PARENTNOTIFY, sent|parent|wparam, WM_LBUTTONDOWN },
1117     { WM_MOUSEACTIVATE, sent },
1118     { WM_MOUSEACTIVATE, sent|parent|defwinproc },
1119     { WM_SETCURSOR, sent },
1120     { WM_SETCURSOR, sent|parent|defwinproc },
1121     { WM_LBUTTONDOWN, posted },
1122     { WM_KILLFOCUS, posted|parent },
1123     { WM_SETFOCUS, posted },
1124     { WM_CTLCOLORBTN, posted|parent },
1125     { BM_SETSTATE, posted },
1126     { WM_CTLCOLORBTN, posted|parent },
1127     { WM_LBUTTONUP, posted },
1128     { BM_SETSTATE, posted },
1129     { WM_CTLCOLORBTN, posted|parent },
1130     { WM_COMMAND, posted|parent },
1131     { 0 }
1132 };
1133 /* Reparenting a button (16/32) */
1134 /* The last child (button) reparented gets topmost for its new parent. */
1135 static const struct message WmReparentButtonSeq[] = { /* FIXME: add */
1136     { WM_SHOWWINDOW, sent|wparam, 0 },
1137     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1138     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1139     { WM_ERASEBKGND, sent|parent },
1140     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1141     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
1142     { WM_CHILDACTIVATE, sent },
1143     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW },
1144     { WM_MOVE, sent|defwinproc },
1145     { WM_SHOWWINDOW, sent|wparam, 1 },
1146     { 0 }
1147 };
1148 /* Creation of a custom dialog (32) */
1149 static const struct message WmCreateCustomDialogSeq[] = {
1150     { HCBT_CREATEWND, hook },
1151     { WM_GETMINMAXINFO, sent },
1152     { WM_NCCREATE, sent },
1153     { WM_NCCALCSIZE, sent|wparam, 0 },
1154     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1155     { WM_CREATE, sent },
1156     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1157     { WM_NOTIFYFORMAT, sent|optional },
1158     { WM_QUERYUISTATE, sent|optional },
1159     { WM_WINDOWPOSCHANGING, sent|optional },
1160     { WM_GETMINMAXINFO, sent|optional },
1161     { WM_NCCALCSIZE, sent|optional },
1162     { WM_WINDOWPOSCHANGED, sent|optional },
1163     { WM_SHOWWINDOW, sent|wparam, 1 },
1164     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1165     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1166     { HCBT_ACTIVATE, hook },
1167     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1168
1169
1170     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1171
1172     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1173
1174     { WM_NCACTIVATE, sent|wparam, 1 },
1175     { WM_GETTEXT, sent|optional|defwinproc },
1176     { WM_GETTEXT, sent|optional|defwinproc },
1177     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
1178     { WM_ACTIVATE, sent|wparam, 1 },
1179     { WM_KILLFOCUS, sent|parent },
1180     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1181     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1182     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1183     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1184     { WM_SETFOCUS, sent },
1185     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1186     { WM_NCPAINT, sent|wparam, 1 },
1187     { WM_GETTEXT, sent|optional|defwinproc },
1188     { WM_GETTEXT, sent|optional|defwinproc },
1189     { WM_ERASEBKGND, sent },
1190     { WM_CTLCOLORDLG, sent|defwinproc },
1191     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1192     { WM_GETTEXT, sent|optional },
1193     { WM_GETTEXT, sent|optional },
1194     { WM_NCCALCSIZE, sent|optional },
1195     { WM_NCPAINT, sent|optional },
1196     { WM_GETTEXT, sent|optional|defwinproc },
1197     { WM_GETTEXT, sent|optional|defwinproc },
1198     { WM_ERASEBKGND, sent|optional },
1199     { WM_CTLCOLORDLG, sent|optional|defwinproc },
1200     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1201     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1202     { WM_MOVE, sent },
1203     { 0 }
1204 };
1205 /* Calling EndDialog for a custom dialog (32) */
1206 static const struct message WmEndCustomDialogSeq[] = {
1207     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1208     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1209     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1210     { WM_GETTEXT, sent|optional },
1211     { HCBT_ACTIVATE, hook },
1212     { WM_NCACTIVATE, sent|wparam, 0 },
1213     { WM_GETTEXT, sent|optional|defwinproc },
1214     { WM_GETTEXT, sent|optional|defwinproc },
1215     { WM_ACTIVATE, sent|wparam, 0 },
1216     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1217     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1218     { HCBT_SETFOCUS, hook },
1219     { WM_KILLFOCUS, sent },
1220     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1221     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1222     { WM_IME_NOTIFY, sent|wparam|optional, 1 },
1223     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1224     { WM_SETFOCUS, sent|parent|defwinproc },
1225     { 0 }
1226 };
1227 /* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
1228 static const struct message WmShowCustomDialogSeq[] = {
1229     { WM_SHOWWINDOW, sent|wparam, 1 },
1230     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1231     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1232     { HCBT_ACTIVATE, hook },
1233     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1234
1235     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1236
1237     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1238     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
1239     { WM_NCACTIVATE, sent|wparam, 1 },
1240     { WM_ACTIVATE, sent|wparam, 1 },
1241
1242     { WM_KILLFOCUS, sent|parent },
1243     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1244     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1245     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1246     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1247     { WM_SETFOCUS, sent },
1248     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1249     { WM_NCPAINT, sent|wparam, 1 },
1250     { WM_ERASEBKGND, sent },
1251     { WM_CTLCOLORDLG, sent|defwinproc },
1252     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1253     { 0 }
1254 };
1255 /* Creation and destruction of a modal dialog (32) */
1256 static const struct message WmModalDialogSeq[] = {
1257     { WM_CANCELMODE, sent|parent },
1258     { HCBT_SETFOCUS, hook },
1259     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1260     { WM_KILLFOCUS, sent|parent },
1261     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1262     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1263     { WM_ENABLE, sent|parent|wparam, 0 },
1264     { HCBT_CREATEWND, hook },
1265     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1266     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1267     { WM_SETFONT, sent },
1268     { WM_INITDIALOG, sent },
1269     { WM_CHANGEUISTATE, sent|optional },
1270     { WM_UPDATEUISTATE, sent|optional },
1271     { WM_SHOWWINDOW, sent },
1272     { HCBT_ACTIVATE, hook },
1273     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1274     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1275     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1276     { WM_NCACTIVATE, sent|wparam, 1 },
1277     { WM_GETTEXT, sent|optional },
1278     { WM_ACTIVATE, sent|wparam, 1 },
1279     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1280     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1281     { WM_NCPAINT, sent },
1282     { WM_GETTEXT, sent|optional },
1283     { WM_ERASEBKGND, sent },
1284     { WM_CTLCOLORDLG, sent },
1285     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1286     { WM_GETTEXT, sent|optional },
1287     { WM_NCCALCSIZE, sent|optional },
1288     { WM_NCPAINT, sent|optional },
1289     { WM_GETTEXT, sent|optional },
1290     { WM_ERASEBKGND, sent|optional },
1291     { WM_CTLCOLORDLG, sent|optional },
1292     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1293     { WM_PAINT, sent|optional },
1294     { WM_CTLCOLORBTN, sent },
1295     { WM_ENTERIDLE, sent|parent|optional },
1296     { WM_ENTERIDLE, sent|parent|optional },
1297     { WM_ENTERIDLE, sent|parent|optional },
1298     { WM_ENTERIDLE, sent|parent|optional },
1299     { WM_ENTERIDLE, sent|parent|optional },
1300     { WM_ENTERIDLE, sent|parent|optional },
1301     { WM_ENTERIDLE, sent|parent|optional },
1302     { WM_ENTERIDLE, sent|parent|optional },
1303     { WM_ENTERIDLE, sent|parent|optional },
1304     { WM_ENTERIDLE, sent|parent|optional },
1305     { WM_ENTERIDLE, sent|parent|optional },
1306     { WM_ENTERIDLE, sent|parent|optional },
1307     { WM_ENTERIDLE, sent|parent|optional },
1308     { WM_ENTERIDLE, sent|parent|optional },
1309     { WM_ENTERIDLE, sent|parent|optional },
1310     { WM_ENTERIDLE, sent|parent|optional },
1311     { WM_ENTERIDLE, sent|parent|optional },
1312     { WM_ENTERIDLE, sent|parent|optional },
1313     { WM_ENTERIDLE, sent|parent|optional },
1314     { WM_ENTERIDLE, sent|parent|optional },
1315     { WM_TIMER, sent },
1316     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1317     { WM_ENABLE, sent|parent|wparam, 1 },
1318     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1319     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1320     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1321     { WM_GETTEXT, sent|optional },
1322     { HCBT_ACTIVATE, hook },
1323     { WM_NCACTIVATE, sent|wparam, 0 },
1324     { WM_GETTEXT, sent|optional },
1325     { WM_ACTIVATE, sent|wparam, 0 },
1326     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1327     { WM_WINDOWPOSCHANGING, sent|optional },
1328     { WM_WINDOWPOSCHANGED, sent|optional },
1329     { HCBT_SETFOCUS, hook },
1330     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1331     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1332     { WM_SETFOCUS, sent|parent|defwinproc },
1333     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 },
1334     { HCBT_DESTROYWND, hook },
1335     { 0x0090, sent|optional },
1336     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1337     { WM_DESTROY, sent },
1338     { WM_NCDESTROY, sent },
1339     { 0 }
1340 };
1341 /* Creation of a modal dialog that is resized inside WM_INITDIALOG (32) */
1342 static const struct message WmCreateModalDialogResizeSeq[] = { /* FIXME: add */
1343     /* (inside dialog proc, handling WM_INITDIALOG) */
1344     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1345     { WM_NCCALCSIZE, sent },
1346     { WM_NCACTIVATE, sent|parent|wparam, 0 },
1347     { WM_GETTEXT, sent|defwinproc },
1348     { WM_ACTIVATE, sent|parent|wparam, 0 },
1349     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1350     { WM_WINDOWPOSCHANGING, sent|parent },
1351     { WM_NCACTIVATE, sent|wparam, 1 },
1352     { WM_ACTIVATE, sent|wparam, 1 },
1353     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1354     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1355     /* (setting focus) */
1356     { WM_SHOWWINDOW, sent|wparam, 1 },
1357     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1358     { WM_NCPAINT, sent },
1359     { WM_GETTEXT, sent|defwinproc },
1360     { WM_ERASEBKGND, sent },
1361     { WM_CTLCOLORDLG, sent|defwinproc },
1362     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1363     { WM_PAINT, sent },
1364     /* (bunch of WM_CTLCOLOR* for each control) */
1365     { WM_PAINT, sent|parent },
1366     { WM_ENTERIDLE, sent|parent|wparam, 0 },
1367     { WM_SETCURSOR, sent|parent },
1368     { 0 }
1369 };
1370 /* SetMenu for NonVisible windows with size change*/
1371 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
1372     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1373     { WM_NCCALCSIZE, sent|wparam, 1 },
1374     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1375     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
1376     { WM_MOVE, sent|defwinproc },
1377     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1378     { WM_NCCALCSIZE,sent|wparam|optional, 1 }, /* XP */
1379     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1380     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1381     { WM_GETTEXT, sent|optional },
1382     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1383     { 0 }
1384 };
1385 /* SetMenu for NonVisible windows with no size change */
1386 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
1387     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1388     { WM_NCCALCSIZE, sent|wparam, 1 },
1389     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1390     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1391     { 0 }
1392 };
1393 /* SetMenu for Visible windows with size change */
1394 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
1395     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1396     { WM_NCCALCSIZE, sent|wparam, 1 },
1397     { 0x0093, sent|defwinproc|optional },
1398     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1399     { WM_NCPAINT, sent }, /* wparam != 1 */
1400     { 0x0093, sent|defwinproc|optional },
1401     { 0x0093, sent|defwinproc|optional },
1402     { 0x0091, sent|defwinproc|optional },
1403     { 0x0092, sent|defwinproc|optional },
1404     { WM_GETTEXT, sent|defwinproc|optional },
1405     { WM_ERASEBKGND, sent|optional },
1406     { WM_ACTIVATE, sent|optional },
1407     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1408     { WM_MOVE, sent|defwinproc },
1409     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1410     { 0x0093, sent|optional },
1411     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1412     { 0x0093, sent|defwinproc|optional },
1413     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1414     { 0x0093, sent|defwinproc|optional },
1415     { 0x0093, sent|defwinproc|optional },
1416     { 0x0091, sent|defwinproc|optional },
1417     { 0x0092, sent|defwinproc|optional },
1418     { WM_ERASEBKGND, sent|optional },
1419     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1420     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1421     { 0 }
1422 };
1423 /* SetMenu for Visible windows with no size change */
1424 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
1425     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1426     { WM_NCCALCSIZE, sent|wparam, 1 },
1427     { WM_NCPAINT, sent }, /* wparam != 1 */
1428     { WM_GETTEXT, sent|defwinproc|optional },
1429     { WM_ERASEBKGND, sent|optional },
1430     { WM_ACTIVATE, sent|optional },
1431     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1432     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1433     { 0 }
1434 };
1435 /* DrawMenuBar for a visible window */
1436 static const struct message WmDrawMenuBarSeq[] =
1437 {
1438     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1439     { WM_NCCALCSIZE, sent|wparam, 1 },
1440     { 0x0093, sent|defwinproc|optional },
1441     { WM_NCPAINT, sent }, /* wparam != 1 */
1442     { 0x0093, sent|defwinproc|optional },
1443     { 0x0093, sent|defwinproc|optional },
1444     { 0x0091, sent|defwinproc|optional },
1445     { 0x0092, sent|defwinproc|optional },
1446     { WM_GETTEXT, sent|defwinproc|optional },
1447     { WM_ERASEBKGND, sent|optional },
1448     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1449     { 0x0093, sent|optional },
1450     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1451     { 0 }
1452 };
1453
1454 static const struct message WmSetRedrawFalseSeq[] =
1455 {
1456     { WM_SETREDRAW, sent|wparam, 0 },
1457     { 0 }
1458 };
1459
1460 static const struct message WmSetRedrawTrueSeq[] =
1461 {
1462     { WM_SETREDRAW, sent|wparam, 1 },
1463     { 0 }
1464 };
1465
1466 static const struct message WmEnableWindowSeq_1[] =
1467 {
1468     { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1469     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1470     { WM_ENABLE, sent|wparam|lparam, FALSE, 0 },
1471     { 0 }
1472 };
1473
1474 static const struct message WmEnableWindowSeq_2[] =
1475 {
1476     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1477     { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
1478     { 0 }
1479 };
1480
1481 static const struct message WmGetScrollRangeSeq[] =
1482 {
1483     { SBM_GETRANGE, sent },
1484     { 0 }
1485 };
1486 static const struct message WmGetScrollInfoSeq[] =
1487 {
1488     { SBM_GETSCROLLINFO, sent },
1489     { 0 }
1490 };
1491 static const struct message WmSetScrollRangeSeq[] =
1492 {
1493     /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
1494        sends SBM_SETSCROLLINFO.
1495      */
1496     { SBM_SETSCROLLINFO, sent },
1497     { 0 }
1498 };
1499 /* SetScrollRange for a window without a non-client area */
1500 static const struct message WmSetScrollRangeHSeq_empty[] =
1501 {
1502     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_HSCROLL, 0 },
1503     { 0 }
1504 };
1505 static const struct message WmSetScrollRangeVSeq_empty[] =
1506 {
1507     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_VSCROLL, 0 },
1508     { 0 }
1509 };
1510 static const struct message WmSetScrollRangeHVSeq[] =
1511 {
1512     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1513     { WM_NCCALCSIZE, sent|wparam, 1 },
1514     { WM_GETTEXT, sent|defwinproc|optional },
1515     { WM_ERASEBKGND, sent|optional },
1516     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1517     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1518     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1519     { 0 }
1520 };
1521 /* SetScrollRange for a window with a non-client area */
1522 static const struct message WmSetScrollRangeHV_NC_Seq[] =
1523 {
1524     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1525     { WM_NCCALCSIZE, sent|wparam, 1 },
1526     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1527     { WM_NCPAINT, sent|optional },
1528     { WM_STYLECHANGING, sent|defwinproc|optional },
1529     { WM_STYLECHANGED, sent|defwinproc|optional },
1530     { WM_STYLECHANGING, sent|defwinproc|optional },
1531     { WM_STYLECHANGED, sent|defwinproc|optional },
1532     { WM_STYLECHANGING, sent|defwinproc|optional },
1533     { WM_STYLECHANGED, sent|defwinproc|optional },
1534     { WM_STYLECHANGING, sent|defwinproc|optional },
1535     { WM_STYLECHANGED, sent|defwinproc|optional },
1536     { WM_GETTEXT, sent|defwinproc|optional },
1537     { WM_GETTEXT, sent|defwinproc|optional },
1538     { WM_ERASEBKGND, sent|optional },
1539     { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
1540     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE },
1541     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1542     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1543     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1544     { WM_GETTEXT, sent|optional },
1545     { WM_GETTEXT, sent|optional },
1546     { WM_GETTEXT, sent|optional },
1547     { WM_GETTEXT, sent|optional },
1548     { 0 }
1549 };
1550 /* test if we receive the right sequence of messages */
1551 /* after calling ShowWindow( SW_SHOWNA) */
1552 static const struct message WmSHOWNAChildInvisParInvis[] = {
1553     { WM_SHOWWINDOW, sent|wparam, 1 },
1554     { 0 }
1555 };
1556 static const struct message WmSHOWNAChildVisParInvis[] = {
1557     { WM_SHOWWINDOW, sent|wparam, 1 },
1558     { 0 }
1559 };
1560 static const struct message WmSHOWNAChildVisParVis[] = {
1561     { WM_SHOWWINDOW, sent|wparam, 1 },
1562     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1563     { 0 }
1564 };
1565 static const struct message WmSHOWNAChildInvisParVis[] = {
1566     { WM_SHOWWINDOW, sent|wparam, 1 },
1567     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1568     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1569     { WM_ERASEBKGND, sent|optional },
1570     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOCLIENTMOVE },
1571     { 0 }
1572 };
1573 static const struct message WmSHOWNATopVisible[] = {
1574     { WM_SHOWWINDOW, sent|wparam, 1 },
1575     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1576     { 0 }
1577 };
1578 static const struct message WmSHOWNATopInvisible[] = {
1579     { WM_NOTIFYFORMAT, sent|optional },
1580     { WM_QUERYUISTATE, sent|optional },
1581     { WM_WINDOWPOSCHANGING, sent|optional },
1582     { WM_GETMINMAXINFO, sent|optional },
1583     { WM_NCCALCSIZE, sent|optional },
1584     { WM_WINDOWPOSCHANGED, sent|optional },
1585     { WM_SHOWWINDOW, sent|wparam, 1 },
1586     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1587     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1588     { WM_NCPAINT, sent|wparam, 1 },
1589     { WM_GETTEXT, sent|defwinproc|optional },
1590     { WM_ERASEBKGND, sent|optional },
1591     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1592     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1593     { WM_NCPAINT, sent|wparam|optional, 1 },
1594     { WM_ERASEBKGND, sent|optional },
1595     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1596     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1597     { WM_MOVE, sent },
1598     { 0 }
1599 };
1600
1601 static int after_end_dialog, test_def_id;
1602 static int sequence_cnt, sequence_size;
1603 static struct message* sequence;
1604 static int log_all_parent_messages;
1605 static int paint_loop_done;
1606
1607 /* user32 functions */
1608 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
1609 static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO);
1610 static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG);
1611 static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO);
1612 static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD);
1613 static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*);
1614 static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
1615 /* kernel32 functions */
1616 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
1617
1618 static void init_procs(void)
1619 {
1620     HMODULE user32 = GetModuleHandleA("user32.dll");
1621     HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
1622
1623 #define GET_PROC(dll, func) \
1624     p ## func = (void*)GetProcAddress(dll, #func); \
1625     if(!p ## func) { \
1626       trace("GetProcAddress(%s) failed\n", #func); \
1627     }
1628
1629     GET_PROC(user32, GetAncestor)
1630     GET_PROC(user32, GetMenuInfo)
1631     GET_PROC(user32, NotifyWinEvent)
1632     GET_PROC(user32, SetMenuInfo)
1633     GET_PROC(user32, SetWinEventHook)
1634     GET_PROC(user32, TrackMouseEvent)
1635     GET_PROC(user32, UnhookWinEvent)
1636
1637     GET_PROC(kernel32, GetCPInfoExA)
1638
1639 #undef GET_PROC
1640 }
1641
1642 static void add_message(const struct message *msg)
1643 {
1644     if (!sequence) 
1645     {
1646         sequence_size = 10;
1647         sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof (struct message) );
1648     }
1649     if (sequence_cnt == sequence_size) 
1650     {
1651         sequence_size *= 2;
1652         sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof (struct message) );
1653     }
1654     assert(sequence);
1655
1656     sequence[sequence_cnt].message = msg->message;
1657     sequence[sequence_cnt].flags = msg->flags;
1658     sequence[sequence_cnt].wParam = msg->wParam;
1659     sequence[sequence_cnt].lParam = msg->lParam;
1660
1661     sequence_cnt++;
1662 }
1663
1664 /* try to make sure pending X events have been processed before continuing */
1665 static void flush_events(void)
1666 {
1667     MSG msg;
1668     int diff = 200;
1669     int min_timeout = 50;
1670     DWORD time = GetTickCount() + diff;
1671
1672     while (diff > 0)
1673     {
1674         if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
1675         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
1676         diff = time - GetTickCount();
1677         min_timeout = 10;
1678     }
1679 }
1680
1681 static void flush_sequence(void)
1682 {
1683     HeapFree(GetProcessHeap(), 0, sequence);
1684     sequence = 0;
1685     sequence_cnt = sequence_size = 0;
1686 }
1687
1688 #define ok_sequence( exp, contx, todo) \
1689         ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
1690
1691
1692 static void ok_sequence_(const struct message *expected, const char *context, int todo,
1693         const char *file, int line)
1694 {
1695     static const struct message end_of_sequence = { 0, 0, 0, 0 };
1696     const struct message *actual;
1697     int failcount = 0;
1698     
1699     add_message(&end_of_sequence);
1700
1701     actual = sequence;
1702
1703     while (expected->message && actual->message)
1704     {
1705         trace_( file, line)("expected %04x - actual %04x\n", expected->message, actual->message);
1706
1707         if (expected->message == actual->message)
1708         {
1709             if (expected->flags & wparam)
1710             {
1711                 if (expected->wParam != actual->wParam && todo)
1712                 {
1713                     todo_wine {
1714                         failcount ++;
1715                         ok_( file, line) (FALSE,
1716                             "%s: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
1717                             context, expected->message, expected->wParam, actual->wParam);
1718                     }
1719                 }
1720                 else
1721                 ok_( file, line) (expected->wParam == actual->wParam,
1722                      "%s: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
1723                      context, expected->message, expected->wParam, actual->wParam);
1724             }
1725             if (expected->flags & lparam)
1726             {
1727                 if (expected->lParam != actual->lParam && todo)
1728                 {
1729                     todo_wine {
1730                         failcount ++;
1731                         ok_( file, line) (FALSE,
1732                             "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
1733                             context, expected->message, expected->lParam, actual->lParam);
1734                     }
1735                 }
1736                 else
1737                  ok_( file, line) (expected->lParam == actual->lParam,
1738                      "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
1739                      context, expected->message, expected->lParam, actual->lParam);
1740             }
1741             if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
1742             {
1743                     todo_wine {
1744                         failcount ++;
1745                         ok_( file, line) (FALSE,
1746                             "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
1747                             context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
1748                     }
1749             }
1750             else
1751                 ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
1752                     "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
1753                     context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
1754             ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
1755                 "%s: the msg 0x%04x should %shave been sent by BeginPaint\n",
1756                 context, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
1757             ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
1758                 "%s: the msg 0x%04x should have been %s\n",
1759                 context, expected->message, (expected->flags & posted) ? "posted" : "sent");
1760             ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
1761                 "%s: the msg 0x%04x was expected in %s\n",
1762                 context, expected->message, (expected->flags & parent) ? "parent" : "child");
1763             ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
1764                 "%s: the msg 0x%04x should have been sent by a hook\n",
1765                 context, expected->message);
1766             ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
1767                 "%s: the msg 0x%04x should have been sent by a winevent hook\n",
1768                 context, expected->message);
1769             expected++;
1770             actual++;
1771         }
1772         /* silently drop winevent messages if there is no support for them */
1773         else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
1774             expected++;
1775         else if (todo)
1776         {
1777             failcount++;
1778             todo_wine {
1779                 ok_( file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
1780                     context, expected->message, actual->message);
1781             }
1782             flush_sequence();
1783             return;
1784         }
1785         else
1786         {
1787             ok_( file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
1788                 context, expected->message, actual->message);
1789             expected++;
1790             actual++;
1791         }
1792     }
1793
1794     /* skip all optional trailing messages */
1795     while (expected->message && ((expected->flags & optional) ||
1796             ((expected->flags & winevent_hook) && !hEvent_hook)))
1797         expected++;
1798
1799     if (todo)
1800     {
1801         todo_wine {
1802             if (expected->message || actual->message) {
1803                 failcount++;
1804                 ok_( file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
1805                     context, expected->message, actual->message);
1806             }
1807         }
1808     }
1809     else
1810     {
1811         if (expected->message || actual->message)
1812             ok_( file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
1813                 context, expected->message, actual->message);
1814     }
1815     if( todo && !failcount) /* succeeded yet marked todo */
1816         todo_wine {
1817             ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
1818         }
1819
1820     flush_sequence();
1821 }
1822
1823 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT))
1824
1825 /******************************** MDI test **********************************/
1826
1827 /* CreateWindow for MDI frame window, initially visible */
1828 static const struct message WmCreateMDIframeSeq[] = {
1829     { HCBT_CREATEWND, hook },
1830     { WM_GETMINMAXINFO, sent },
1831     { WM_NCCREATE, sent },
1832     { WM_NCCALCSIZE, sent|wparam, 0 },
1833     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1834     { WM_CREATE, sent },
1835     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1836     { WM_NOTIFYFORMAT, sent|optional },
1837     { WM_QUERYUISTATE, sent|optional },
1838     { WM_WINDOWPOSCHANGING, sent|optional },
1839     { WM_GETMINMAXINFO, sent|optional },
1840     { WM_NCCALCSIZE, sent|optional },
1841     { WM_WINDOWPOSCHANGED, sent|optional },
1842     { WM_SHOWWINDOW, sent|wparam, 1 },
1843     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1844     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1845     { HCBT_ACTIVATE, hook },
1846     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1847     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1848     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
1849     { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
1850     { WM_NCACTIVATE, sent|wparam, 1 },
1851     { WM_GETTEXT, sent|defwinproc|optional },
1852     { WM_ACTIVATE, sent|wparam, 1 },
1853     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
1854     { HCBT_SETFOCUS, hook },
1855     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1856     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1857     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1858     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
1859     /* Win9x adds SWP_NOZORDER below */
1860     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1861     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
1862     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1863     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1864     { WM_MOVE, sent },
1865     { 0 }
1866 };
1867 /* DestroyWindow for MDI frame window, initially visible */
1868 static const struct message WmDestroyMDIframeSeq[] = {
1869     { HCBT_DESTROYWND, hook },
1870     { 0x0090, sent|optional },
1871     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1872     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1873     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
1874     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1875     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
1876     { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
1877     { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
1878     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
1879     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1880     { WM_DESTROY, sent },
1881     { WM_NCDESTROY, sent },
1882     { 0 }
1883 };
1884 /* CreateWindow for MDI client window, initially visible */
1885 static const struct message WmCreateMDIclientSeq[] = {
1886     { HCBT_CREATEWND, hook },
1887     { WM_NCCREATE, sent },
1888     { WM_NCCALCSIZE, sent|wparam, 0 },
1889     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
1890     { WM_CREATE, sent },
1891     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
1892     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1893     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1894     { WM_MOVE, sent },
1895     { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
1896     { WM_SHOWWINDOW, sent|wparam, 1 },
1897     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1898     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1899     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1900     { 0 }
1901 };
1902 /* ShowWindow(SW_SHOW) for MDI client window */
1903 static const struct message WmShowMDIclientSeq[] = {
1904     { WM_SHOWWINDOW, sent|wparam, 1 },
1905     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1906     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1907     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1908     { 0 }
1909 };
1910 /* ShowWindow(SW_HIDE) for MDI client window */
1911 static const struct message WmHideMDIclientSeq[] = {
1912     { WM_SHOWWINDOW, sent|wparam, 0 },
1913     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1914     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
1915     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
1916     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1917     { 0 }
1918 };
1919 /* DestroyWindow for MDI client window, initially visible */
1920 static const struct message WmDestroyMDIclientSeq[] = {
1921     { HCBT_DESTROYWND, hook },
1922     { 0x0090, sent|optional },
1923     { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
1924     { WM_SHOWWINDOW, sent|wparam, 0 },
1925     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1926     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1927     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1928     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1929     { WM_DESTROY, sent },
1930     { WM_NCDESTROY, sent },
1931     { 0 }
1932 };
1933 /* CreateWindow for MDI child window, initially visible */
1934 static const struct message WmCreateMDIchildVisibleSeq[] = {
1935     { HCBT_CREATEWND, hook },
1936     { WM_NCCREATE, sent }, 
1937     { WM_NCCALCSIZE, sent|wparam, 0 },
1938     { WM_CREATE, sent },
1939     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1940     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1941     { WM_MOVE, sent },
1942     /* Win2k sends wparam set to
1943      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1944      * while Win9x doesn't bother to set child window id according to
1945      * CLIENTCREATESTRUCT.idFirstChild
1946      */
1947     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1948     { WM_SHOWWINDOW, sent|wparam, 1 },
1949     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1950     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1951     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1952     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1953     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1954     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1955     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1956
1957     /* Win9x: message sequence terminates here. */
1958
1959     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1960     { HCBT_SETFOCUS, hook }, /* in MDI client */
1961     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1962     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
1963     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1964     { WM_SETFOCUS, sent }, /* in MDI client */
1965     { HCBT_SETFOCUS, hook },
1966     { WM_KILLFOCUS, sent }, /* in MDI client */
1967     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1968     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1969     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1970     { WM_SETFOCUS, sent|defwinproc },
1971     { WM_MDIACTIVATE, sent|defwinproc },
1972     { 0 }
1973 };
1974 /* CreateWindow for MDI child window with invisible parent */
1975 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
1976     { HCBT_CREATEWND, hook },
1977     { WM_GETMINMAXINFO, sent },
1978     { WM_NCCREATE, sent }, 
1979     { WM_NCCALCSIZE, sent|wparam, 0 },
1980     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
1981     { WM_CREATE, sent },
1982     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1983     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1984     { WM_MOVE, sent },
1985     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1986     { WM_SHOWWINDOW, sent|wparam, 1 },
1987     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
1988     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1989     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1990     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1991
1992     /* Win9x: message sequence terminates here. */
1993
1994     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1995     { HCBT_SETFOCUS, hook }, /* in MDI client */
1996     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1997     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
1998     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1999     { WM_SETFOCUS, sent }, /* in MDI client */
2000     { HCBT_SETFOCUS, hook },
2001     { WM_KILLFOCUS, sent }, /* in MDI client */
2002     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2003     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2004     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2005     { WM_SETFOCUS, sent|defwinproc },
2006     { WM_MDIACTIVATE, sent|defwinproc },
2007     { 0 }
2008 };
2009 /* DestroyWindow for MDI child window, initially visible */
2010 static const struct message WmDestroyMDIchildVisibleSeq[] = {
2011     { HCBT_DESTROYWND, hook },
2012     /* Win2k sends wparam set to
2013      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2014      * while Win9x doesn't bother to set child window id according to
2015      * CLIENTCREATESTRUCT.idFirstChild
2016      */
2017     { 0x0090, sent|optional },
2018     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2019     { WM_SHOWWINDOW, sent|wparam, 0 },
2020     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2021     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2022     { WM_ERASEBKGND, sent|parent|optional },
2023     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2024
2025     /* { WM_DESTROY, sent }
2026      * Win9x: message sequence terminates here.
2027      */
2028
2029     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2030     { WM_KILLFOCUS, sent },
2031     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2032     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2033     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2034     { WM_SETFOCUS, sent }, /* in MDI client */
2035
2036     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2037     { WM_KILLFOCUS, sent }, /* in MDI client */
2038     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2039     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2040     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2041     { WM_SETFOCUS, sent }, /* in MDI client */
2042
2043     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2044
2045     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2046     { WM_KILLFOCUS, sent },
2047     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2048     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2049     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2050     { WM_SETFOCUS, sent }, /* in MDI client */
2051
2052     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2053     { WM_KILLFOCUS, sent }, /* in MDI client */
2054     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2055     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2056     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2057     { WM_SETFOCUS, sent }, /* in MDI client */
2058
2059     { WM_DESTROY, sent },
2060
2061     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2062     { WM_KILLFOCUS, sent },
2063     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2064     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2065     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2066     { WM_SETFOCUS, sent }, /* in MDI client */
2067
2068     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2069     { WM_KILLFOCUS, sent }, /* in MDI client */
2070     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2071     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2072     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2073     { WM_SETFOCUS, sent }, /* in MDI client */
2074
2075     { WM_NCDESTROY, sent },
2076     { 0 }
2077 };
2078 /* CreateWindow for MDI child window, initially invisible */
2079 static const struct message WmCreateMDIchildInvisibleSeq[] = {
2080     { HCBT_CREATEWND, hook },
2081     { WM_NCCREATE, sent }, 
2082     { WM_NCCALCSIZE, sent|wparam, 0 },
2083     { WM_CREATE, sent },
2084     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2085     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2086     { WM_MOVE, sent },
2087     /* Win2k sends wparam set to
2088      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2089      * while Win9x doesn't bother to set child window id according to
2090      * CLIENTCREATESTRUCT.idFirstChild
2091      */
2092     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2093     { 0 }
2094 };
2095 /* DestroyWindow for MDI child window, initially invisible */
2096 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
2097     { HCBT_DESTROYWND, hook },
2098     /* Win2k sends wparam set to
2099      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2100      * while Win9x doesn't bother to set child window id according to
2101      * CLIENTCREATESTRUCT.idFirstChild
2102      */
2103     { 0x0090, sent|optional },
2104     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2105     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2106     { WM_DESTROY, sent },
2107     { WM_NCDESTROY, sent },
2108     /* FIXME: Wine destroys an icon/title window while Windows doesn't */
2109     { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */
2110     { 0 }
2111 };
2112 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
2113 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
2114     { HCBT_CREATEWND, hook },
2115     { WM_NCCREATE, sent }, 
2116     { WM_NCCALCSIZE, sent|wparam, 0 },
2117     { WM_CREATE, sent },
2118     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2119     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2120     { WM_MOVE, sent },
2121     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2122     { WM_GETMINMAXINFO, sent },
2123     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED  },
2124     { WM_NCCALCSIZE, sent|wparam, 1 },
2125     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2126     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2127      /* in MDI frame */
2128     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2129     { WM_NCCALCSIZE, sent|wparam, 1 },
2130     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2131     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2132     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2133     /* Win2k sends wparam set to
2134      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2135      * while Win9x doesn't bother to set child window id according to
2136      * CLIENTCREATESTRUCT.idFirstChild
2137      */
2138     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2139     { WM_SHOWWINDOW, sent|wparam, 1 },
2140     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2141     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2142     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2143     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2144     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2145     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2146     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2147
2148     /* Win9x: message sequence terminates here. */
2149
2150     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2151     { HCBT_SETFOCUS, hook }, /* in MDI client */
2152     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2153     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2154     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2155     { WM_SETFOCUS, sent }, /* in MDI client */
2156     { HCBT_SETFOCUS, hook },
2157     { WM_KILLFOCUS, sent }, /* in MDI client */
2158     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2159     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2160     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2161     { WM_SETFOCUS, sent|defwinproc },
2162     { WM_MDIACTIVATE, sent|defwinproc },
2163      /* in MDI frame */
2164     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2165     { WM_NCCALCSIZE, sent|wparam, 1 },
2166     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2167     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2168     { 0 }
2169 };
2170 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
2171 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
2172     /* restore the 1st MDI child */
2173     { WM_SETREDRAW, sent|wparam, 0 },
2174     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2175     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2176     { WM_NCCALCSIZE, sent|wparam, 1 },
2177     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2178     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2179     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2180      /* in MDI frame */
2181     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2182     { WM_NCCALCSIZE, sent|wparam, 1 },
2183     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2184     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2185     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2186     { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
2187     /* create the 2nd MDI child */
2188     { HCBT_CREATEWND, hook },
2189     { WM_NCCREATE, sent }, 
2190     { WM_NCCALCSIZE, sent|wparam, 0 },
2191     { WM_CREATE, sent },
2192     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2193     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2194     { WM_MOVE, sent },
2195     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2196     { WM_GETMINMAXINFO, sent },
2197     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2198     { WM_NCCALCSIZE, sent|wparam, 1 },
2199     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2200     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2201     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2202      /* in MDI frame */
2203     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2204     { WM_NCCALCSIZE, sent|wparam, 1 },
2205     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2206     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2207     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2208     /* Win2k sends wparam set to
2209      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2210      * while Win9x doesn't bother to set child window id according to
2211      * CLIENTCREATESTRUCT.idFirstChild
2212      */
2213     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2214     { WM_SHOWWINDOW, sent|wparam, 1 },
2215     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2216     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2217     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2218     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2219     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2220     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2221
2222     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2223     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2224
2225     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2226
2227     /* Win9x: message sequence terminates here. */
2228
2229     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2230     { HCBT_SETFOCUS, hook },
2231     { WM_KILLFOCUS, sent|defwinproc|optional }, /* in the 1st MDI child */
2232     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
2233     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2234     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2235     { WM_SETFOCUS, sent }, /* in MDI client */
2236     { HCBT_SETFOCUS, hook },
2237     { WM_KILLFOCUS, sent }, /* in MDI client */
2238     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2239     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2240     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2241     { WM_SETFOCUS, sent|defwinproc },
2242
2243     { WM_MDIACTIVATE, sent|defwinproc },
2244      /* in MDI frame */
2245     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2246     { WM_NCCALCSIZE, sent|wparam, 1 },
2247     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2248     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2249     { 0 }
2250 };
2251 /* WM_MDICREATE MDI child window, initially visible and maximized */
2252 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
2253     { WM_MDICREATE, sent },
2254     { HCBT_CREATEWND, hook },
2255     { WM_NCCREATE, sent }, 
2256     { WM_NCCALCSIZE, sent|wparam, 0 },
2257     { WM_CREATE, sent },
2258     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2259     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2260     { WM_MOVE, sent },
2261     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2262     { WM_GETMINMAXINFO, sent },
2263     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2264     { WM_NCCALCSIZE, sent|wparam, 1 },
2265     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2266     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2267
2268      /* in MDI frame */
2269     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2270     { WM_NCCALCSIZE, sent|wparam, 1 },
2271     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2272     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2273     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2274
2275     /* Win2k sends wparam set to
2276      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2277      * while Win9x doesn't bother to set child window id according to
2278      * CLIENTCREATESTRUCT.idFirstChild
2279      */
2280     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2281     { WM_SHOWWINDOW, sent|wparam, 1 },
2282     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2283
2284     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2285
2286     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2287     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2288     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2289
2290     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2291     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2292
2293     /* Win9x: message sequence terminates here. */
2294
2295     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2296     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2297     { HCBT_SETFOCUS, hook }, /* in MDI client */
2298     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2299     { WM_IME_NOTIFY, sent|wparam|optional, 2 },
2300     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
2301     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2302     { HCBT_SETFOCUS, hook|optional },
2303     { WM_KILLFOCUS, sent }, /* in MDI client */
2304     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2305     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2306     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2307     { WM_SETFOCUS, sent|defwinproc },
2308
2309     { WM_MDIACTIVATE, sent|defwinproc },
2310
2311      /* in MDI child */
2312     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2313     { WM_NCCALCSIZE, sent|wparam, 1 },
2314     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2315     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2316
2317      /* in MDI frame */
2318     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2319     { WM_NCCALCSIZE, sent|wparam, 1 },
2320     { 0x0093, sent|defwinproc|optional },
2321     { 0x0093, sent|defwinproc|optional },
2322     { 0x0093, sent|defwinproc|optional },
2323     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2324     { WM_MOVE, sent|defwinproc },
2325     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2326
2327      /* in MDI client */
2328     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2329     { WM_NCCALCSIZE, sent|wparam, 1 },
2330     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2331     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2332
2333      /* in MDI child */
2334     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2335     { WM_NCCALCSIZE, sent|wparam, 1 },
2336     { 0x0093, sent|optional },
2337     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2338     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2339
2340     { 0x0093, sent|optional },
2341     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2342     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2343     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
2344     { 0x0093, sent|defwinproc|optional },
2345     { 0x0093, sent|defwinproc|optional },
2346     { 0x0093, sent|defwinproc|optional },
2347     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2348     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2349
2350     { 0 }
2351 };
2352 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
2353 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
2354     { HCBT_CREATEWND, hook },
2355     { WM_GETMINMAXINFO, sent },
2356     { WM_NCCREATE, sent }, 
2357     { WM_NCCALCSIZE, sent|wparam, 0 },
2358     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2359     { WM_CREATE, sent },
2360     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2361     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2362     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE|SWP_NOMOVE }, /* MDI frame */
2363     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI frame */
2364     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* MDI frame */
2365     { WM_MOVE, sent },
2366     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2367     { WM_GETMINMAXINFO, sent },
2368     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2369     { WM_GETMINMAXINFO, sent|defwinproc },
2370     { WM_NCCALCSIZE, sent|wparam, 1 },
2371     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_STATECHANGED },
2372     { WM_MOVE, sent|defwinproc },
2373     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2374      /* in MDI frame */
2375     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2376     { WM_NCCALCSIZE, sent|wparam, 1 },
2377     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2378     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2379     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
2380     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2381     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2382     /* Win2k sends wparam set to
2383      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2384      * while Win9x doesn't bother to set child window id according to
2385      * CLIENTCREATESTRUCT.idFirstChild
2386      */
2387     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2388     { 0 }
2389 };
2390 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
2391 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
2392     { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
2393     { HCBT_SYSCOMMAND, hook },
2394     { WM_CLOSE, sent|defwinproc },
2395     { WM_MDIDESTROY, sent }, /* in MDI client */
2396
2397     /* bring the 1st MDI child to top */
2398     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
2399     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
2400
2401     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2402
2403     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
2404     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2405     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2406
2407     /* maximize the 1st MDI child */
2408     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2409     { WM_GETMINMAXINFO, sent|defwinproc },
2410     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED },
2411     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2412     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
2413     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2414     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2415
2416     /* restore the 2nd MDI child */
2417     { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
2418     { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
2419     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
2420     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2421
2422     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2423
2424     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2425     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2426
2427     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2428
2429     { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
2430      /* in MDI frame */
2431     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2432     { WM_NCCALCSIZE, sent|wparam, 1 },
2433     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2434     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2435     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2436
2437     /* bring the 1st MDI child to top */
2438     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2439     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2440     { HCBT_SETFOCUS, hook },
2441     { WM_KILLFOCUS, sent|defwinproc },
2442     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
2443     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2444     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2445     { WM_SETFOCUS, sent }, /* in MDI client */
2446     { HCBT_SETFOCUS, hook },
2447     { WM_KILLFOCUS, sent }, /* in MDI client */
2448     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2449     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2450     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2451     { WM_SETFOCUS, sent|defwinproc },
2452     { WM_MDIACTIVATE, sent|defwinproc },
2453     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2454
2455     /* apparently ShowWindow(SW_SHOW) on an MDI client */
2456     { WM_SHOWWINDOW, sent|wparam, 1 },
2457     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2458     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2459     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2460     { WM_MDIREFRESHMENU, sent },
2461
2462     { HCBT_DESTROYWND, hook },
2463     /* Win2k sends wparam set to
2464      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2465      * while Win9x doesn't bother to set child window id according to
2466      * CLIENTCREATESTRUCT.idFirstChild
2467      */
2468     { 0x0090, sent|defwinproc|optional },
2469     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2470     { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
2471     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2472     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2473     { WM_ERASEBKGND, sent|parent|optional },
2474     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2475
2476     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2477     { WM_DESTROY, sent|defwinproc },
2478     { WM_NCDESTROY, sent|defwinproc },
2479     { 0 }
2480 };
2481 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
2482 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
2483     { WM_MDIDESTROY, sent }, /* in MDI client */
2484     { WM_SHOWWINDOW, sent|wparam, 0 },
2485     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2486     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2487     { WM_ERASEBKGND, sent|parent|optional },
2488     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2489
2490     { HCBT_SETFOCUS, hook },
2491     { WM_KILLFOCUS, sent },
2492     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2493     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2494     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2495     { WM_SETFOCUS, sent }, /* in MDI client */
2496     { HCBT_SETFOCUS, hook },
2497     { WM_KILLFOCUS, sent }, /* in MDI client */
2498     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2499     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2500     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2501     { WM_SETFOCUS, sent },
2502
2503      /* in MDI child */
2504     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2505     { WM_NCCALCSIZE, sent|wparam, 1 },
2506     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2507     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2508
2509      /* in MDI frame */
2510     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2511     { WM_NCCALCSIZE, sent|wparam, 1 },
2512     { 0x0093, sent|defwinproc|optional },
2513     { 0x0093, sent|defwinproc|optional },
2514     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2515     { WM_MOVE, sent|defwinproc },
2516     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2517
2518      /* in MDI client */
2519     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2520     { WM_NCCALCSIZE, sent|wparam, 1 },
2521     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2522     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2523
2524      /* in MDI child */
2525     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2526     { WM_NCCALCSIZE, sent|wparam, 1 },
2527     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2528     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2529
2530      /* in MDI child */
2531     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2532     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2533     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2534     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2535
2536      /* in MDI frame */
2537     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2538     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2539     { 0x0093, sent|defwinproc|optional },
2540     { 0x0093, sent|defwinproc|optional },
2541     { 0x0093, sent|defwinproc|optional },
2542     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2543     { WM_MOVE, sent|defwinproc },
2544     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2545
2546      /* in MDI client */
2547     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2548     { WM_NCCALCSIZE, sent|wparam, 1 },
2549     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2550     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2551
2552      /* in MDI child */
2553     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
2554     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2555     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2556     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2557     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2558     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2559
2560     { 0x0093, sent|defwinproc|optional },
2561     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
2562     { 0x0093, sent|defwinproc|optional },
2563     { 0x0093, sent|defwinproc|optional },
2564     { 0x0093, sent|defwinproc|optional },
2565     { 0x0093, sent|optional },
2566
2567     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2568     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2569     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2570     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2571     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2572
2573      /* in MDI frame */
2574     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2575     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
2576     { 0x0093, sent|defwinproc|optional },
2577     { 0x0093, sent|defwinproc|optional },
2578     { 0x0093, sent|defwinproc|optional },
2579     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2580     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2581     { 0x0093, sent|optional },
2582
2583     { WM_NCACTIVATE, sent|wparam, 0 },
2584     { WM_MDIACTIVATE, sent },
2585
2586     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2587     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
2588     { WM_NCCALCSIZE, sent|wparam, 1 },
2589
2590     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2591
2592     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2593     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2594     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2595
2596      /* in MDI child */
2597     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2598     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2599     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2600     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2601
2602      /* in MDI frame */
2603     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2604     { WM_NCCALCSIZE, sent|wparam, 1 },
2605     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2606     { WM_MOVE, sent|defwinproc },
2607     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2608
2609      /* in MDI client */
2610     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2611     { WM_NCCALCSIZE, sent|wparam, 1 },
2612     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2613     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2614     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2615     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2616     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2617     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2618     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2619
2620     { HCBT_SETFOCUS, hook },
2621     { WM_KILLFOCUS, sent },
2622     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2623     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2624     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2625     { WM_SETFOCUS, sent }, /* in MDI client */
2626
2627     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2628
2629     { HCBT_DESTROYWND, hook },
2630     /* Win2k sends wparam set to
2631      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2632      * while Win9x doesn't bother to set child window id according to
2633      * CLIENTCREATESTRUCT.idFirstChild
2634      */
2635     { 0x0090, sent|optional },
2636     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2637
2638     { WM_SHOWWINDOW, sent|wparam, 0 },
2639     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2640     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2641     { WM_ERASEBKGND, sent|parent|optional },
2642     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2643
2644     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2645     { WM_DESTROY, sent },
2646     { WM_NCDESTROY, sent },
2647     { 0 }
2648 };
2649 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
2650 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
2651     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2652     { WM_GETMINMAXINFO, sent },
2653     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
2654     { WM_NCCALCSIZE, sent|wparam, 1 },
2655     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2656     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2657
2658     { WM_WINDOWPOSCHANGING, sent|wparam|optional|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2659     { WM_NCACTIVATE, sent|wparam|optional|defwinproc, 1 },
2660     { HCBT_SETFOCUS, hook|optional },
2661     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2662     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2663     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2664     { HCBT_SETFOCUS, hook|optional },
2665     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
2666     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2667     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2668     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2669     { WM_SETFOCUS, sent|optional|defwinproc },
2670     { WM_MDIACTIVATE, sent|optional|defwinproc },
2671     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2672     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2673      /* in MDI frame */
2674     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2675     { WM_NCCALCSIZE, sent|wparam, 1 },
2676     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2677     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2678     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2679     { 0 }
2680 };
2681 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
2682 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
2683     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2684     { WM_GETMINMAXINFO, sent },
2685     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
2686     { WM_GETMINMAXINFO, sent|defwinproc },
2687     { WM_NCCALCSIZE, sent|wparam, 1 },
2688     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2689     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2690
2691     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2692     { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
2693     { HCBT_SETFOCUS, hook },
2694     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2695     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2696     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2697     { HCBT_SETFOCUS, hook|optional },
2698     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
2699     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2700     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2701     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2702     { WM_SETFOCUS, sent|defwinproc|optional },
2703     { WM_MDIACTIVATE, sent|defwinproc|optional },
2704     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2705     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2706     { 0 }
2707 };
2708 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
2709 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
2710     { WM_MDIMAXIMIZE, sent }, /* in MDI client */
2711     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2712     { WM_GETMINMAXINFO, sent },
2713     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2714     { WM_GETMINMAXINFO, sent|defwinproc },
2715     { WM_NCCALCSIZE, sent|wparam, 1 },
2716     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
2717     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2718     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
2719     { WM_MOVE, sent|defwinproc },
2720     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2721
2722     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2723     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2724     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2725     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
2726     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2727     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
2728      /* in MDI frame */
2729     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2730     { WM_NCCALCSIZE, sent|wparam, 1 },
2731     { 0x0093, sent|defwinproc|optional },
2732     { 0x0094, sent|defwinproc|optional },
2733     { 0x0094, sent|defwinproc|optional },
2734     { 0x0094, sent|defwinproc|optional },
2735     { 0x0094, sent|defwinproc|optional },
2736     { 0x0093, sent|defwinproc|optional },
2737     { 0x0093, sent|defwinproc|optional },
2738     { 0x0091, sent|defwinproc|optional },
2739     { 0x0092, sent|defwinproc|optional },
2740     { 0x0092, sent|defwinproc|optional },
2741     { 0x0092, sent|defwinproc|optional },
2742     { 0x0092, sent|defwinproc|optional },
2743     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2744     { WM_MOVE, sent|defwinproc },
2745     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2746     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
2747      /* in MDI client */
2748     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2749     { WM_NCCALCSIZE, sent|wparam, 1 },
2750     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2751     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2752      /* in MDI child */
2753     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
2754     { WM_GETMINMAXINFO, sent|defwinproc },
2755     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2756     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2757     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2758     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
2759     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
2760     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2761     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2762     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
2763      /* in MDI frame */
2764     { 0x0093, sent|optional },
2765     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
2766     { 0x0093, sent|defwinproc|optional },
2767     { 0x0093, sent|defwinproc|optional },
2768     { 0x0093, sent|defwinproc|optional },
2769     { 0x0091, sent|defwinproc|optional },
2770     { 0x0092, sent|defwinproc|optional },
2771     { 0x0092, sent|defwinproc|optional },
2772     { 0x0092, sent|defwinproc|optional },
2773     { 0x0092, sent|defwinproc|optional },
2774     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
2775     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
2776     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2777     { 0 }
2778 };
2779 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
2780 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
2781     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2782     { WM_GETMINMAXINFO, sent },
2783     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2784     { WM_NCCALCSIZE, sent|wparam, 1 },
2785     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2786     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2787     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2788      /* in MDI frame */
2789     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2790     { WM_NCCALCSIZE, sent|wparam, 1 },
2791     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2792     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2793     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2794     { 0 }
2795 };
2796 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
2797 static const struct message WmRestoreMDIchildVisibleSeq[] = {
2798     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
2799     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2800     { WM_NCCALCSIZE, sent|wparam, 1 },
2801     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2802     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2803     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2804      /* in MDI frame */
2805     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2806     { WM_NCCALCSIZE, sent|wparam, 1 },
2807     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2808     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2809     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2810     { 0 }
2811 };
2812 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
2813 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
2814     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
2815     { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
2816     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
2817     { WM_NCCALCSIZE, sent|wparam, 1 },
2818     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2819     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_NOCLIENTSIZE|SWP_STATECHANGED },
2820     { WM_MOVE, sent|defwinproc },
2821     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2822     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2823     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2824     { HCBT_SETFOCUS, hook },
2825     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2826     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2827     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2828     { WM_SETFOCUS, sent },
2829     { 0 }
2830 };
2831 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
2832 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
2833     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
2834     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
2835     { WM_NCCALCSIZE, sent|wparam, 1 },
2836     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOCLIENTSIZE|SWP_STATECHANGED },
2837     { WM_MOVE, sent|defwinproc },
2838     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
2839     { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
2840     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2841     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2842     /* FIXME: Wine creates an icon/title window while Windows doesn't */
2843     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */
2844     { 0 }
2845 };
2846 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
2847 static const struct message WmRestoreMDIchildInisibleSeq[] = {
2848     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
2849     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED  },
2850     { WM_NCCALCSIZE, sent|wparam, 1 },
2851     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2852     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2853     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2854     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2855      /* in MDI frame */
2856     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2857     { WM_NCCALCSIZE, sent|wparam, 1 },
2858     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2859     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2860     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2861     { 0 }
2862 };
2863
2864 static HWND mdi_client;
2865 static WNDPROC old_mdi_client_proc;
2866
2867 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2868 {
2869     struct message msg;
2870
2871     /* do not log painting messages */
2872     if (message != WM_PAINT &&
2873         message != WM_NCPAINT &&
2874         message != WM_SYNCPAINT &&
2875         message != WM_ERASEBKGND &&
2876         message != WM_NCHITTEST &&
2877         message != WM_GETTEXT &&
2878         message != WM_MDIGETACTIVE &&
2879         message != WM_GETICON &&
2880         message != WM_DEVICECHANGE)
2881     {
2882         trace("mdi client: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
2883
2884         switch (message)
2885         {
2886             case WM_WINDOWPOSCHANGING:
2887             case WM_WINDOWPOSCHANGED:
2888             {
2889                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
2890
2891                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
2892                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
2893                       winpos->hwnd, winpos->hwndInsertAfter,
2894                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
2895                 dump_winpos_flags(winpos->flags);
2896
2897                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2898                  * in the high word for internal purposes
2899                  */
2900                 wParam = winpos->flags & 0xffff;
2901                 /* We are not interested in the flags that don't match under XP and Win9x */
2902                 wParam &= ~(SWP_NOZORDER);
2903                 break;
2904             }
2905         }
2906
2907         msg.message = message;
2908         msg.flags = sent|wparam|lparam;
2909         msg.wParam = wParam;
2910         msg.lParam = lParam;
2911         add_message(&msg);
2912     }
2913
2914     return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
2915 }
2916
2917 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2918 {
2919     static long defwndproc_counter = 0;
2920     LRESULT ret;
2921     struct message msg;
2922
2923     /* do not log painting messages */
2924     if (message != WM_PAINT &&
2925         message != WM_NCPAINT &&
2926         message != WM_SYNCPAINT &&
2927         message != WM_ERASEBKGND &&
2928         message != WM_NCHITTEST &&
2929         message != WM_GETTEXT &&
2930         message != WM_GETICON &&
2931         message != WM_DEVICECHANGE)
2932     {
2933         trace("mdi child: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
2934
2935         switch (message)
2936         {
2937             case WM_WINDOWPOSCHANGING:
2938             case WM_WINDOWPOSCHANGED:
2939             {
2940                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
2941
2942                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
2943                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
2944                       winpos->hwnd, winpos->hwndInsertAfter,
2945                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
2946                 dump_winpos_flags(winpos->flags);
2947
2948                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2949                  * in the high word for internal purposes
2950                  */
2951                 wParam = winpos->flags & 0xffff;
2952                 /* We are not interested in the flags that don't match under XP and Win9x */
2953                 wParam &= ~(SWP_NOZORDER);
2954                 break;
2955             }
2956
2957             case WM_MDIACTIVATE:
2958             {
2959                 HWND active, client = GetParent(hwnd);
2960
2961                 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
2962
2963                 if (hwnd == (HWND)lParam) /* if we are being activated */
2964                     ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
2965                 else
2966                     ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
2967                 break;
2968             }
2969         }
2970
2971         msg.message = message;
2972         msg.flags = sent|wparam|lparam;
2973         if (defwndproc_counter) msg.flags |= defwinproc;
2974         msg.wParam = wParam;
2975         msg.lParam = lParam;
2976         add_message(&msg);
2977     }
2978
2979     defwndproc_counter++;
2980     ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
2981     defwndproc_counter--;
2982
2983     return ret;
2984 }
2985
2986 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2987 {
2988     static long defwndproc_counter = 0;
2989     LRESULT ret;
2990     struct message msg;
2991
2992     /* do not log painting messages */
2993     if (message != WM_PAINT &&
2994         message != WM_NCPAINT &&
2995         message != WM_SYNCPAINT &&
2996         message != WM_ERASEBKGND &&
2997         message != WM_NCHITTEST &&
2998         message != WM_GETTEXT &&
2999         message != WM_GETICON &&
3000         message != WM_DEVICECHANGE &&
3001         message < 0xc000)
3002     {
3003         trace("mdi frame: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
3004
3005         switch (message)
3006         {
3007             case WM_WINDOWPOSCHANGING:
3008             case WM_WINDOWPOSCHANGED:
3009             {
3010                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
3011
3012                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
3013                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
3014                       winpos->hwnd, winpos->hwndInsertAfter,
3015                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
3016                 dump_winpos_flags(winpos->flags);
3017
3018                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
3019                  * in the high word for internal purposes
3020                  */
3021                 wParam = winpos->flags & 0xffff;
3022                 /* We are not interested in the flags that don't match under XP and Win9x */
3023                 wParam &= ~(SWP_NOZORDER);
3024                 break;
3025             }
3026         }
3027
3028         msg.message = message;
3029         msg.flags = sent|wparam|lparam;
3030         if (defwndproc_counter) msg.flags |= defwinproc;
3031         msg.wParam = wParam;
3032         msg.lParam = lParam;
3033         add_message(&msg);
3034     }
3035
3036     defwndproc_counter++;
3037     ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
3038     defwndproc_counter--;
3039
3040     return ret;
3041 }
3042
3043 static BOOL mdi_RegisterWindowClasses(void)
3044 {
3045     WNDCLASSA cls;
3046
3047     cls.style = 0;
3048     cls.lpfnWndProc = mdi_frame_wnd_proc;
3049     cls.cbClsExtra = 0;
3050     cls.cbWndExtra = 0;
3051     cls.hInstance = GetModuleHandleA(0);
3052     cls.hIcon = 0;
3053     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
3054     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
3055     cls.lpszMenuName = NULL;
3056     cls.lpszClassName = "MDI_frame_class";
3057     if (!RegisterClassA(&cls)) return FALSE;
3058
3059     cls.lpfnWndProc = mdi_child_wnd_proc;
3060     cls.lpszClassName = "MDI_child_class";
3061     if (!RegisterClassA(&cls)) return FALSE;
3062
3063     if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
3064     old_mdi_client_proc = cls.lpfnWndProc;
3065     cls.hInstance = GetModuleHandleA(0);
3066     cls.lpfnWndProc = mdi_client_hook_proc;
3067     cls.lpszClassName = "MDI_client_class";
3068     if (!RegisterClassA(&cls)) assert(0);
3069
3070     return TRUE;
3071 }
3072
3073 static void test_mdi_messages(void)
3074 {
3075     MDICREATESTRUCTA mdi_cs;
3076     CLIENTCREATESTRUCT client_cs;
3077     HWND mdi_frame, mdi_child, mdi_child2, active_child;
3078     BOOL zoomed;
3079     HMENU hMenu = CreateMenu();
3080
3081     assert(mdi_RegisterWindowClasses());
3082
3083     flush_sequence();
3084
3085     trace("creating MDI frame window\n");
3086     mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
3087                                 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
3088                                 WS_MAXIMIZEBOX | WS_VISIBLE,
3089                                 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
3090                                 GetDesktopWindow(), hMenu,
3091                                 GetModuleHandleA(0), NULL);
3092     assert(mdi_frame);
3093     ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
3094
3095     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3096     ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
3097
3098     trace("creating MDI client window\n");
3099     client_cs.hWindowMenu = 0;
3100     client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
3101     mdi_client = CreateWindowExA(0, "MDI_client_class",
3102                                  NULL,
3103                                  WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
3104                                  0, 0, 0, 0,
3105                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3106     assert(mdi_client);
3107     ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
3108
3109     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3110     ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
3111
3112     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3113     ok(!active_child, "wrong active MDI child %p\n", active_child);
3114     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3115
3116     SetFocus(0);
3117     flush_sequence();
3118
3119     trace("creating invisible MDI child window\n");
3120     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3121                                 WS_CHILD,
3122                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3123                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3124     assert(mdi_child);
3125
3126     flush_sequence();
3127     ShowWindow(mdi_child, SW_SHOWNORMAL);
3128     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
3129
3130     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3131     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3132
3133     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3134     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3135
3136     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3137     ok(!active_child, "wrong active MDI child %p\n", active_child);
3138     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3139
3140     ShowWindow(mdi_child, SW_HIDE);
3141     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
3142     flush_sequence();
3143
3144     ShowWindow(mdi_child, SW_SHOW);
3145     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
3146
3147     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3148     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3149
3150     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3151     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3152
3153     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3154     ok(!active_child, "wrong active MDI child %p\n", active_child);
3155     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3156
3157     DestroyWindow(mdi_child);
3158     flush_sequence();
3159
3160     trace("creating visible MDI child window\n");
3161     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3162                                 WS_CHILD | WS_VISIBLE,
3163                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3164                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3165     assert(mdi_child);
3166     ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
3167
3168     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3169     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3170
3171     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3172     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3173
3174     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3175     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3176     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3177     flush_sequence();
3178
3179     DestroyWindow(mdi_child);
3180     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3181
3182     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3183     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3184
3185     /* Win2k: MDI client still returns a just destroyed child as active
3186      * Win9x: MDI client returns 0
3187      */
3188     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3189     ok(active_child == mdi_child || /* win2k */
3190        !active_child, /* win9x */
3191        "wrong active MDI child %p\n", active_child);
3192     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3193
3194     flush_sequence();
3195
3196     trace("creating invisible MDI child window\n");
3197     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3198                                 WS_CHILD,
3199                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3200                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3201     assert(mdi_child2);
3202     ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
3203
3204     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
3205     ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
3206
3207     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3208     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3209
3210     /* Win2k: MDI client still returns a just destroyed child as active
3211      * Win9x: MDI client returns mdi_child2
3212      */
3213     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3214     ok(active_child == mdi_child || /* win2k */
3215        active_child == mdi_child2, /* win9x */
3216        "wrong active MDI child %p\n", active_child);
3217     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3218     flush_sequence();
3219
3220     ShowWindow(mdi_child2, SW_MAXIMIZE);
3221     ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
3222
3223     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3224     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3225
3226     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3227     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3228     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3229     flush_sequence();
3230
3231     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3232     ok(GetFocus() == mdi_child2 || /* win2k */
3233        GetFocus() == 0, /* win9x */
3234        "wrong focus window %p\n", GetFocus());
3235
3236     SetFocus(0);
3237     flush_sequence();
3238
3239     ShowWindow(mdi_child2, SW_HIDE);
3240     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3241
3242     ShowWindow(mdi_child2, SW_RESTORE);
3243     ok_sequence(WmRestoreMDIchildInisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
3244     flush_sequence();
3245
3246     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3247     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3248
3249     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3250     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3251     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3252     flush_sequence();
3253
3254     SetFocus(0);
3255     flush_sequence();
3256
3257     ShowWindow(mdi_child2, SW_HIDE);
3258     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3259
3260     ShowWindow(mdi_child2, SW_SHOW);
3261     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
3262
3263     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3264     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3265
3266     ShowWindow(mdi_child2, SW_MAXIMIZE);
3267     ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
3268
3269     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3270     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3271
3272     ShowWindow(mdi_child2, SW_RESTORE);
3273     ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
3274
3275     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3276     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3277
3278     ShowWindow(mdi_child2, SW_MINIMIZE);
3279     ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", TRUE);
3280
3281     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3282     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3283
3284     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3285     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3286     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3287     flush_sequence();
3288
3289     ShowWindow(mdi_child2, SW_RESTORE);
3290     ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", TRUE);
3291
3292     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3293     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3294
3295     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3296     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3297     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3298     flush_sequence();
3299
3300     SetFocus(0);
3301     flush_sequence();
3302
3303     ShowWindow(mdi_child2, SW_HIDE);
3304     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3305
3306     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3307     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3308
3309     DestroyWindow(mdi_child2);
3310     ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
3311
3312     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3313     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3314
3315     /* test for maximized MDI children */
3316     trace("creating maximized visible MDI child window 1\n");
3317     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3318                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3319                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3320                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3321     assert(mdi_child);
3322     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
3323     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3324
3325     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3326     ok(GetFocus() == mdi_child || /* win2k */
3327        GetFocus() == 0, /* win9x */
3328        "wrong focus window %p\n", GetFocus());
3329
3330     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3331     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3332     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3333     flush_sequence();
3334
3335     trace("creating maximized visible MDI child window 2\n");
3336     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3337                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3338                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3339                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3340     assert(mdi_child2);
3341     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3342     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3343     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3344
3345     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3346     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3347
3348     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3349     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3350     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3351     flush_sequence();
3352
3353     trace("destroying maximized visible MDI child window 2\n");
3354     DestroyWindow(mdi_child2);
3355     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3356
3357     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3358
3359     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3360     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3361
3362     /* Win2k: MDI client still returns a just destroyed child as active
3363      * Win9x: MDI client returns 0
3364      */
3365     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3366     ok(active_child == mdi_child2 || /* win2k */
3367        !active_child, /* win9x */
3368        "wrong active MDI child %p\n", active_child);
3369     flush_sequence();
3370
3371     ShowWindow(mdi_child, SW_MAXIMIZE);
3372     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3373     flush_sequence();
3374
3375     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3376     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3377
3378     trace("re-creating maximized visible MDI child window 2\n");
3379     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3380                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3381                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3382                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3383     assert(mdi_child2);
3384     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3385     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3386     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3387
3388     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3389     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3390
3391     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3392     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3393     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3394     flush_sequence();
3395
3396     SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
3397     ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
3398     ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
3399
3400     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3401     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3402     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3403
3404     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3405     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3406     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3407     flush_sequence();
3408
3409     DestroyWindow(mdi_child);
3410     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3411
3412     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3413     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3414
3415     /* Win2k: MDI client still returns a just destroyed child as active
3416      * Win9x: MDI client returns 0
3417      */
3418     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3419     ok(active_child == mdi_child || /* win2k */
3420        !active_child, /* win9x */
3421        "wrong active MDI child %p\n", active_child);
3422     flush_sequence();
3423
3424     trace("creating maximized invisible MDI child window\n");
3425     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3426                                 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
3427                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3428                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3429     assert(mdi_child2);
3430     ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", FALSE);
3431     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3432     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
3433     ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
3434
3435     /* Win2k: MDI client still returns a just destroyed child as active
3436      * Win9x: MDI client returns 0
3437      */
3438     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3439     ok(active_child == mdi_child || /* win2k */
3440        !active_child, /* win9x */
3441        "wrong active MDI child %p\n", active_child);
3442     flush_sequence();
3443
3444     trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
3445     ShowWindow(mdi_child2, SW_MAXIMIZE);
3446     ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
3447     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3448     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3449     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3450
3451     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3452     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3453     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3454     flush_sequence();
3455
3456     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3457     flush_sequence();
3458
3459     /* end of test for maximized MDI children */
3460     SetFocus(0);
3461     flush_sequence();
3462     trace("creating maximized visible MDI child window 1(Switch test)\n");
3463     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3464                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3465                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3466                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3467     assert(mdi_child);
3468     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE);
3469     ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n");
3470
3471     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3472     ok(GetFocus() == mdi_child || /* win2k */
3473        GetFocus() == 0, /* win9x */
3474        "wrong focus window %p(Switch test)\n", GetFocus());
3475
3476     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3477     ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3478     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3479     flush_sequence();
3480
3481     trace("creating maximized visible MDI child window 2(Switch test)\n");
3482     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3483                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3484                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3485                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3486     assert(mdi_child2);
3487     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child window (Switch test)", TRUE);
3488
3489     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n");
3490     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized(Switch test)\n");
3491
3492     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3493     ok(GetFocus() == mdi_child2, "wrong focus window %p(Switch test)\n", GetFocus());
3494
3495     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3496     ok(active_child == mdi_child2, "wrong active MDI child %p(Switch test)\n", active_child);
3497     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3498     flush_sequence();
3499
3500     trace("Switch child window.\n");
3501     SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0);
3502     ok_sequence(WmSwitchChild, "Child did not switch correctly", TRUE);
3503     trace("end of test for switch maximized MDI children\n");
3504     flush_sequence();
3505
3506     /* Prepare for switching test of not maximized MDI children  */
3507     ShowWindow( mdi_child, SW_NORMAL );
3508     ok(!IsZoomed(mdi_child), "wrong zoomed state for %p(Switch test)\n", mdi_child);
3509     ok(!IsZoomed(mdi_child2), "wrong zoomed state for %p(Switch test)\n", mdi_child2);
3510     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
3511     ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3512     flush_sequence();
3513
3514     SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child2, 0);
3515     ok_sequence(WmSwitchNotMaximizedChild, "Not maximized child did not switch correctly", FALSE);
3516     trace("end of test for switch not maximized MDI children\n");
3517     flush_sequence();
3518
3519     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3520     flush_sequence();
3521
3522     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3523     flush_sequence();
3524
3525     SetFocus(0);
3526     flush_sequence();
3527     /* end of tests for switch maximized/not maximized MDI children */
3528
3529     mdi_cs.szClass = "MDI_child_Class";
3530     mdi_cs.szTitle = "MDI child";
3531     mdi_cs.hOwner = GetModuleHandleA(0);
3532     mdi_cs.x = 0;
3533     mdi_cs.y = 0;
3534     mdi_cs.cx = CW_USEDEFAULT;
3535     mdi_cs.cy = CW_USEDEFAULT;
3536     mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
3537     mdi_cs.lParam = 0;
3538     mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
3539     ok(mdi_child != 0, "MDI child creation failed\n");
3540     ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
3541
3542     ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
3543
3544     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3545     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3546
3547     ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
3548     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3549     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3550
3551     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3552     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3553     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3554     flush_sequence();
3555
3556     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3557     ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
3558
3559     ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
3560     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3561     ok(!active_child, "wrong active MDI child %p\n", active_child);
3562
3563     SetFocus(0);
3564     flush_sequence();
3565
3566     DestroyWindow(mdi_client);
3567     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3568
3569     /* test maximization of MDI child with invisible parent */
3570     client_cs.hWindowMenu = 0;
3571     mdi_client = CreateWindow("MDI_client_class",
3572                                  NULL,
3573                                  WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
3574                                  0, 0, 660, 430,
3575                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3576     ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
3577
3578     ShowWindow(mdi_client, SW_HIDE);
3579     ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
3580
3581     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3582                                 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
3583                                 0, 0, 650, 440,
3584                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3585     ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
3586
3587     SendMessage(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
3588     ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
3589     zoomed = IsZoomed(mdi_child);
3590     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3591     
3592     ShowWindow(mdi_client, SW_SHOW);
3593     ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
3594
3595     DestroyWindow(mdi_child);
3596     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
3597
3598     /* end of test for maximization of MDI child with invisible parent */
3599
3600     DestroyWindow(mdi_client);
3601     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3602
3603     DestroyWindow(mdi_frame);
3604     ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
3605 }
3606 /************************* End of MDI test **********************************/
3607
3608 static void test_WM_SETREDRAW(HWND hwnd)
3609 {
3610     DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
3611
3612     flush_events();
3613     flush_sequence();
3614
3615     SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3616     ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
3617
3618     ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
3619     ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
3620
3621     flush_sequence();
3622     SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3623     ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
3624
3625     ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
3626     ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
3627
3628     /* restore original WS_VISIBLE state */
3629     SetWindowLongA(hwnd, GWL_STYLE, style);
3630
3631     flush_events();
3632     flush_sequence();
3633 }
3634
3635 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3636 {
3637     struct message msg;
3638
3639     trace("dialog: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
3640
3641     /* explicitly ignore WM_GETICON message */
3642     if (message == WM_GETICON) return 0;
3643
3644     /* ignore registered messages */
3645     if (message >= 0xc000) return 0;
3646
3647     switch (message)
3648     {
3649         /* ignore */
3650         case WM_MOUSEMOVE:
3651         case WM_SETCURSOR:
3652         case WM_DEVICECHANGE:
3653             return 0;
3654         case WM_NCHITTEST:
3655             return HTCLIENT;
3656
3657         case WM_WINDOWPOSCHANGING:
3658         case WM_WINDOWPOSCHANGED:
3659         {
3660             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
3661
3662             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
3663             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
3664                   winpos->hwnd, winpos->hwndInsertAfter,
3665                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
3666             dump_winpos_flags(winpos->flags);
3667
3668             /* Log only documented flags, win2k uses 0x1000 and 0x2000
3669              * in the high word for internal purposes
3670              */
3671             wParam = winpos->flags & 0xffff;
3672             /* We are not interested in the flags that don't match under XP and Win9x */
3673             wParam &= ~(SWP_NOZORDER);
3674             break;
3675         }
3676     }
3677
3678     msg.message = message;
3679     msg.flags = sent|wparam|lparam;
3680     msg.wParam = wParam;
3681     msg.lParam = lParam;
3682     add_message(&msg);
3683
3684     if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
3685     if (message == WM_TIMER) EndDialog( hwnd, 0 );
3686     return 0;
3687 }
3688
3689 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
3690 {
3691     DWORD style, exstyle;
3692     INT xmin, xmax;
3693     BOOL ret;
3694
3695     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
3696     style = GetWindowLongA(hwnd, GWL_STYLE);
3697     /* do not be confused by WS_DLGFRAME set */
3698     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
3699
3700     if (clear) ok(style & clear, "style %08x should be set\n", clear);
3701     if (set) ok(!(style & set), "style %08x should not be set\n", set);
3702
3703     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3704     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
3705     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
3706         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
3707     else
3708         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
3709
3710     style = GetWindowLongA(hwnd, GWL_STYLE);
3711     if (set) ok(style & set, "style %08x should be set\n", set);
3712     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
3713
3714     /* a subsequent call should do nothing */
3715     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3716     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
3717     ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3718
3719     xmin = 0xdeadbeef;
3720     xmax = 0xdeadbeef;
3721     trace("Ignore GetScrollRange error below if you are on Win9x\n");
3722     ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
3723     ok( ret, "GetScrollRange(%d) error %d\n", ctl, GetLastError());
3724     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3725     ok(xmin == min, "unexpected min scroll value %d\n", xmin);
3726     ok(xmax == max, "unexpected max scroll value %d\n", xmax);
3727 }
3728
3729 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
3730 {
3731     DWORD style, exstyle;
3732     SCROLLINFO si;
3733     BOOL ret;
3734
3735     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
3736     style = GetWindowLongA(hwnd, GWL_STYLE);
3737     /* do not be confused by WS_DLGFRAME set */
3738     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
3739
3740     if (clear) ok(style & clear, "style %08x should be set\n", clear);
3741     if (set) ok(!(style & set), "style %08x should not be set\n", set);
3742
3743     si.cbSize = sizeof(si);
3744     si.fMask = SIF_RANGE;
3745     si.nMin = min;
3746     si.nMax = max;
3747     SetScrollInfo(hwnd, ctl, &si, TRUE);
3748     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
3749         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
3750     else
3751         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
3752
3753     style = GetWindowLongA(hwnd, GWL_STYLE);
3754     if (set) ok(style & set, "style %08x should be set\n", set);
3755     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
3756
3757     /* a subsequent call should do nothing */
3758     SetScrollInfo(hwnd, ctl, &si, TRUE);
3759     if (style & WS_HSCROLL)
3760         ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3761     else if (style & WS_VSCROLL)
3762         ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3763     else
3764         ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3765
3766     si.fMask = SIF_PAGE;
3767     si.nPage = 5;
3768     SetScrollInfo(hwnd, ctl, &si, FALSE);
3769     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3770
3771     si.fMask = SIF_POS;
3772     si.nPos = max - 1;
3773     SetScrollInfo(hwnd, ctl, &si, FALSE);
3774     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3775
3776     si.fMask = SIF_RANGE;
3777     si.nMin = 0xdeadbeef;
3778     si.nMax = 0xdeadbeef;
3779     ret = GetScrollInfo(hwnd, ctl, &si);
3780     ok( ret, "GetScrollInfo error %d\n", GetLastError());
3781     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3782     ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
3783     ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
3784 }
3785
3786 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
3787 static void test_scroll_messages(HWND hwnd)
3788 {
3789     SCROLLINFO si;
3790     INT min, max;
3791     BOOL ret;
3792
3793     flush_events();
3794     flush_sequence();
3795
3796     min = 0xdeadbeef;
3797     max = 0xdeadbeef;
3798     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
3799     ok( ret, "GetScrollRange error %d\n", GetLastError());
3800     if (sequence->message != WmGetScrollRangeSeq[0].message)
3801         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
3802     /* values of min and max are undefined */
3803     flush_sequence();
3804
3805     ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
3806     ok( ret, "SetScrollRange error %d\n", GetLastError());
3807     if (sequence->message != WmSetScrollRangeSeq[0].message)
3808         trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
3809     flush_sequence();
3810
3811     min = 0xdeadbeef;
3812     max = 0xdeadbeef;
3813     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
3814     ok( ret, "GetScrollRange error %d\n", GetLastError());
3815     if (sequence->message != WmGetScrollRangeSeq[0].message)
3816         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
3817     /* values of min and max are undefined */
3818     flush_sequence();
3819
3820     si.cbSize = sizeof(si);
3821     si.fMask = SIF_RANGE;
3822     si.nMin = 20;
3823     si.nMax = 160;
3824     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
3825     if (sequence->message != WmSetScrollRangeSeq[0].message)
3826         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3827     flush_sequence();
3828
3829     si.fMask = SIF_PAGE;
3830     si.nPage = 10;
3831     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
3832     if (sequence->message != WmSetScrollRangeSeq[0].message)
3833         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3834     flush_sequence();
3835
3836     si.fMask = SIF_POS;
3837     si.nPos = 20;
3838     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
3839     if (sequence->message != WmSetScrollRangeSeq[0].message)
3840         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3841     flush_sequence();
3842
3843     si.fMask = SIF_RANGE;
3844     si.nMin = 0xdeadbeef;
3845     si.nMax = 0xdeadbeef;
3846     ret = GetScrollInfo(hwnd, SB_CTL, &si);
3847     ok( ret, "GetScrollInfo error %d\n", GetLastError());
3848     if (sequence->message != WmGetScrollInfoSeq[0].message)
3849         trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3850     /* values of min and max are undefined */
3851     flush_sequence();
3852
3853     /* set WS_HSCROLL */
3854     test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
3855     /* clear WS_HSCROLL */
3856     test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
3857
3858     /* set WS_HSCROLL */
3859     test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
3860     /* clear WS_HSCROLL */
3861     test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
3862
3863     /* set WS_VSCROLL */
3864     test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
3865     /* clear WS_VSCROLL */
3866     test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
3867
3868     /* set WS_VSCROLL */
3869     test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
3870     /* clear WS_VSCROLL */
3871     test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
3872 }
3873
3874 static void test_showwindow(void)
3875 {
3876     HWND hwnd, hchild;
3877     RECT rc;
3878
3879     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
3880                            100, 100, 200, 200, 0, 0, 0, NULL);
3881     ok (hwnd != 0, "Failed to create overlapped window\n");
3882     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
3883                              0, 0, 10, 10, hwnd, 0, 0, NULL);
3884     ok (hchild != 0, "Failed to create child\n");
3885     flush_sequence();
3886
3887     /* ShowWindow( SW_SHOWNA) for invisible top level window */
3888     trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
3889     ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
3890     ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", TRUE);
3891     trace("done\n");
3892
3893     /* ShowWindow( SW_SHOWNA) for now visible top level window */
3894     trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
3895     ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
3896     ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
3897     trace("done\n");
3898     /* back to invisible */
3899     ShowWindow(hchild, SW_HIDE);
3900     ShowWindow(hwnd, SW_HIDE);
3901     flush_sequence();
3902     /* ShowWindow(SW_SHOWNA) with child and parent invisible */ 
3903     trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
3904     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
3905     ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
3906     trace("done\n");
3907     /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */ 
3908     ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
3909     flush_sequence();
3910     trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
3911     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
3912     ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
3913     trace("done\n");
3914     /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
3915     ShowWindow( hwnd, SW_SHOW);
3916     flush_sequence();
3917     trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
3918     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
3919     ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
3920     trace("done\n");
3921
3922     /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
3923     ShowWindow( hchild, SW_HIDE);
3924     flush_sequence();
3925     trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
3926     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
3927     ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
3928     trace("done\n");
3929
3930     SetCapture(hchild);
3931     ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
3932     DestroyWindow(hchild);
3933     ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
3934
3935     DestroyWindow(hwnd);
3936     flush_sequence();
3937
3938     /* Popup windows */
3939     /* Test 1:
3940      * 1. Create invisible maximized popup window.
3941      * 2. Move and resize it.
3942      * 3. Show it maximized.
3943      */
3944     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
3945     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
3946                            100, 100, 200, 200, 0, 0, 0, NULL);
3947     ok (hwnd != 0, "Failed to create popup window\n");
3948     ok(IsZoomed(hwnd), "window should be maximized\n");
3949     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
3950     trace("done\n");
3951
3952     GetWindowRect(hwnd, &rc);
3953     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
3954         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
3955         "Invalid maximized size before ShowWindow (%d,%d)-(%d,%d)\n",
3956         rc.left, rc.top, rc.right, rc.bottom);
3957     /* Reset window's size & position */
3958     SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
3959     ok(IsZoomed(hwnd), "window should be maximized\n");
3960     flush_sequence();
3961
3962     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
3963     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
3964     ok(IsZoomed(hwnd), "window should be maximized\n");
3965     ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
3966     trace("done\n");
3967
3968     GetWindowRect(hwnd, &rc);
3969     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
3970         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
3971         "Invalid maximized size after ShowWindow (%d,%d)-(%d,%d)\n",
3972         rc.left, rc.top, rc.right, rc.bottom);
3973     DestroyWindow(hwnd);
3974     flush_sequence();
3975
3976     /* Test 2:
3977      * 1. Create invisible maximized popup window.
3978      * 2. Show it maximized.
3979      */
3980     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
3981     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
3982                            100, 100, 200, 200, 0, 0, 0, NULL);
3983     ok (hwnd != 0, "Failed to create popup window\n");
3984     ok(IsZoomed(hwnd), "window should be maximized\n");
3985     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
3986     trace("done\n");
3987
3988     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
3989     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
3990     ok(IsZoomed(hwnd), "window should be maximized\n");
3991     ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
3992     trace("done\n");
3993     DestroyWindow(hwnd);
3994     flush_sequence();
3995
3996     /* Test 3:
3997      * 1. Create visible maximized popup window.
3998      */
3999     trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
4000     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
4001                            100, 100, 200, 200, 0, 0, 0, NULL);
4002     ok (hwnd != 0, "Failed to create popup window\n");
4003     ok(IsZoomed(hwnd), "window should be maximized\n");
4004     ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4005     trace("done\n");
4006     DestroyWindow(hwnd);
4007     flush_sequence();
4008
4009     /* Test 4:
4010      * 1. Create visible popup window.
4011      * 2. Maximize it.
4012      */
4013     trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
4014     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
4015                            100, 100, 200, 200, 0, 0, 0, NULL);
4016     ok (hwnd != 0, "Failed to create popup window\n");
4017     ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
4018     ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE);
4019     trace("done\n");
4020
4021     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
4022     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4023     ok(IsZoomed(hwnd), "window should be maximized\n");
4024     ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
4025     trace("done\n");
4026     DestroyWindow(hwnd);
4027     flush_sequence();
4028 }
4029
4030 static void test_sys_menu(void)
4031 {
4032     HWND hwnd;
4033     HMENU hmenu;
4034     UINT state;
4035
4036     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4037                            100, 100, 200, 200, 0, 0, 0, NULL);
4038     ok (hwnd != 0, "Failed to create overlapped window\n");
4039
4040     flush_sequence();
4041
4042     /* test existing window without CS_NOCLOSE style */
4043     hmenu = GetSystemMenu(hwnd, FALSE);
4044     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4045
4046     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4047     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4048     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4049
4050     EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
4051     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4052
4053     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4054     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4055     ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
4056
4057     EnableMenuItem(hmenu, SC_CLOSE, 0);
4058     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4059
4060     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4061     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4062     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4063
4064     /* test whether removing WS_SYSMENU destroys a system menu */
4065     SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
4066     SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4067     flush_sequence();
4068     hmenu = GetSystemMenu(hwnd, FALSE);
4069     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4070
4071     DestroyWindow(hwnd);
4072
4073     /* test new window with CS_NOCLOSE style */
4074     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4075                            100, 100, 200, 200, 0, 0, 0, NULL);
4076     ok (hwnd != 0, "Failed to create overlapped window\n");
4077
4078     hmenu = GetSystemMenu(hwnd, FALSE);
4079     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4080
4081     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4082     ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4083
4084     DestroyWindow(hwnd);
4085
4086     /* test new window without WS_SYSMENU style */
4087     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
4088                            100, 100, 200, 200, 0, 0, 0, NULL);
4089     ok(hwnd != 0, "Failed to create overlapped window\n");
4090
4091     hmenu = GetSystemMenu(hwnd, FALSE);
4092     ok(!hmenu, "GetSystemMenu error %d\n", GetLastError());
4093
4094     DestroyWindow(hwnd);
4095 }
4096
4097 /* For shown WS_OVERLAPPEDWINDOW */
4098 static const struct message WmSetIcon_1[] = {
4099     { WM_SETICON, sent },
4100     { 0x00AE, sent|defwinproc|optional }, /* XP */
4101     { WM_GETTEXT, sent|defwinproc|optional },
4102     { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
4103     { 0 }
4104 };
4105
4106 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
4107 static const struct message WmSetIcon_2[] = {
4108     { WM_SETICON, sent },
4109     { 0 }
4110 };
4111
4112 /* Sending undocumented 0x3B message with wparam = 0x8000000b */
4113 static const struct message WmInitEndSession[] = {
4114     { 0x003B, sent },
4115     { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4116     { 0 }
4117 };
4118
4119 /* Sending undocumented 0x3B message with wparam = 0x0000000b */
4120 static const struct message WmInitEndSession_2[] = {
4121     { 0x003B, sent },
4122     { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4123     { 0 }
4124 };
4125
4126 /* Sending undocumented 0x3B message with wparam = 0x80000008 */
4127 static const struct message WmInitEndSession_3[] = {
4128     { 0x003B, sent },
4129     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4130     { 0 }
4131 };
4132
4133 /* Sending undocumented 0x3B message with wparam = 0x00000008 */
4134 static const struct message WmInitEndSession_4[] = {
4135     { 0x003B, sent },
4136     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4137     { 0 }
4138 };
4139
4140 /* Sending undocumented 0x3B message with wparam = 0x80000001 */
4141 static const struct message WmInitEndSession_5[] = {
4142     { 0x003B, sent },
4143     { WM_ENDSESSION, sent|defwinproc/*|wparam*/|lparam, 1, ENDSESSION_LOGOFF },
4144     { 0 }
4145 };
4146
4147 static const struct message WmZOrder[] = {
4148     { WM_WINDOWPOSCHANGING, sent|wparam, 0, 0 },
4149     { WM_GETMINMAXINFO, sent|defwinproc|wparam, 0, 0 },
4150     { HCBT_ACTIVATE, hook },
4151     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
4152     { WM_WINDOWPOSCHANGING, sent|wparam, 3, 0 },
4153     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0 },
4154     { WM_GETTEXT, sent|optional },
4155     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
4156     { WM_ACTIVATEAPP, sent|wparam, 1, 0 },
4157     { WM_NCACTIVATE, sent|wparam|lparam, 1, 0 },
4158     { WM_GETTEXT, sent|defwinproc|optional },
4159     { WM_GETTEXT, sent|defwinproc|optional },
4160     { WM_ACTIVATE, sent|wparam|lparam, 1, 0 },
4161     { HCBT_SETFOCUS, hook },
4162     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
4163     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4164     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
4165     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
4166     { WM_GETTEXT, sent|optional },
4167     { WM_NCCALCSIZE, sent|optional },
4168     { 0 }
4169 };
4170
4171 static void test_MsgWaitForMultipleObjects(HWND hwnd)
4172 {
4173     DWORD ret;
4174     MSG msg;
4175
4176     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4177     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4178
4179     PostMessageA(hwnd, WM_USER, 0, 0);
4180
4181     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4182     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4183
4184     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4185     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4186
4187     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4188     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4189
4190     PostMessageA(hwnd, WM_USER, 0, 0);
4191
4192     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4193     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4194
4195     ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
4196     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4197
4198     /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
4199     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4200     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4201
4202     PostMessageA(hwnd, WM_USER, 0, 0);
4203
4204     /* new incoming message causes it to become signaled again */
4205     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4206     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4207
4208     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4209     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4210     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4211     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4212 }
4213
4214 /* test if we receive the right sequence of messages */
4215 static void test_messages(void)
4216 {
4217     HWND hwnd, hparent, hchild;
4218     HWND hchild2, hbutton;
4219     HMENU hmenu;
4220     MSG msg;
4221     LRESULT res;
4222
4223     flush_sequence();
4224
4225     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4226                            100, 100, 200, 200, 0, 0, 0, NULL);
4227     ok (hwnd != 0, "Failed to create overlapped window\n");
4228     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4229
4230     /* test ShowWindow(SW_HIDE) on a newly created invisible window */
4231     ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
4232     ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
4233
4234     /* test WM_SETREDRAW on a not visible top level window */
4235     test_WM_SETREDRAW(hwnd);
4236
4237     SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4238     flush_events();
4239     ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
4240     ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
4241
4242     ok(GetActiveWindow() == hwnd, "window should be active\n");
4243     ok(GetFocus() == hwnd, "window should have input focus\n");
4244     ShowWindow(hwnd, SW_HIDE);
4245     flush_events();
4246     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
4247
4248     ShowWindow(hwnd, SW_SHOW);
4249     flush_events();
4250     ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
4251
4252     ShowWindow(hwnd, SW_HIDE);
4253     flush_events();
4254     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
4255
4256     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4257     flush_events();
4258     ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
4259
4260     ShowWindow(hwnd, SW_RESTORE);
4261     ok_sequence(WmShowRestoreMaxOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", FALSE);
4262     flush_events();
4263     flush_sequence();
4264
4265     ShowWindow(hwnd, SW_MINIMIZE);
4266     flush_events();
4267     ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE);
4268     flush_sequence();
4269
4270     ShowWindow(hwnd, SW_RESTORE);
4271     flush_events();
4272     ok_sequence(WmShowRestoreMinOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
4273     flush_sequence();
4274
4275     ShowWindow(hwnd, SW_SHOW);
4276     flush_events();
4277     ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
4278
4279     ok(GetActiveWindow() == hwnd, "window should be active\n");
4280     ok(GetFocus() == hwnd, "window should have input focus\n");
4281     SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4282     ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
4283     ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
4284     ok(GetActiveWindow() == hwnd, "window should still be active\n");
4285
4286     /* test WM_SETREDRAW on a visible top level window */
4287     ShowWindow(hwnd, SW_SHOW);
4288     flush_events();
4289     test_WM_SETREDRAW(hwnd);
4290
4291     trace("testing scroll APIs on a visible top level window %p\n", hwnd);
4292     test_scroll_messages(hwnd);
4293
4294     /* test resizing and moving */
4295     SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
4296     ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
4297     flush_events();
4298     flush_sequence();
4299     SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
4300     ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
4301     flush_events();
4302     flush_sequence();
4303     SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER|SWP_NOACTIVATE );
4304     ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
4305     flush_events();
4306     flush_sequence();
4307
4308     /* popups don't get WM_GETMINMAXINFO */
4309     SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
4310     SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4311     flush_sequence();
4312     SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
4313     ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
4314
4315     DestroyWindow(hwnd);
4316     ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
4317
4318     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4319                               100, 100, 200, 200, 0, 0, 0, NULL);
4320     ok (hparent != 0, "Failed to create parent window\n");
4321     flush_sequence();
4322
4323     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
4324                              0, 0, 10, 10, hparent, 0, 0, NULL);
4325     ok (hchild != 0, "Failed to create child window\n");
4326     ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
4327     DestroyWindow(hchild);
4328     flush_sequence();
4329
4330     /* visible child window with a caption */
4331     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
4332                              WS_CHILD | WS_VISIBLE | WS_CAPTION,
4333                              0, 0, 10, 10, hparent, 0, 0, NULL);
4334     ok (hchild != 0, "Failed to create child window\n");
4335     ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
4336
4337     trace("testing scroll APIs on a visible child window %p\n", hchild);
4338     test_scroll_messages(hchild);
4339
4340     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4341     ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
4342
4343     DestroyWindow(hchild);
4344     flush_sequence();
4345
4346     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4347                              0, 0, 10, 10, hparent, 0, 0, NULL);
4348     ok (hchild != 0, "Failed to create child window\n");
4349     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4350     
4351     hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
4352                                100, 100, 50, 50, hparent, 0, 0, NULL);
4353     ok (hchild2 != 0, "Failed to create child2 window\n");
4354     flush_sequence();
4355
4356     hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
4357                               0, 100, 50, 50, hchild, 0, 0, NULL);
4358     ok (hbutton != 0, "Failed to create button window\n");
4359
4360     /* test WM_SETREDRAW on a not visible child window */
4361     test_WM_SETREDRAW(hchild);
4362
4363     ShowWindow(hchild, SW_SHOW);
4364     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4365
4366     /* check parent messages too */
4367     log_all_parent_messages++;
4368     ShowWindow(hchild, SW_HIDE);
4369     ok_sequence(WmHideChildSeq2, "ShowWindow(SW_HIDE):child", FALSE);
4370     log_all_parent_messages--;
4371
4372     ShowWindow(hchild, SW_SHOW);
4373     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4374
4375     ShowWindow(hchild, SW_HIDE);
4376     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
4377
4378     ShowWindow(hchild, SW_SHOW);
4379     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4380
4381     /* test WM_SETREDRAW on a visible child window */
4382     test_WM_SETREDRAW(hchild);
4383
4384     log_all_parent_messages++;
4385     MoveWindow(hchild, 10, 10, 20, 20, TRUE);
4386     ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
4387     log_all_parent_messages--;
4388
4389     ShowWindow(hchild, SW_HIDE);
4390     flush_sequence();
4391     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4392     ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
4393
4394     ShowWindow(hchild, SW_HIDE);
4395     flush_sequence();
4396     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
4397     ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
4398
4399     /* DestroyWindow sequence below expects that a child has focus */
4400     SetFocus(hchild);
4401     flush_sequence();
4402
4403     DestroyWindow(hchild);
4404     ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
4405     DestroyWindow(hchild2);
4406     DestroyWindow(hbutton);
4407
4408     flush_sequence();
4409     hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
4410                              0, 0, 100, 100, hparent, 0, 0, NULL);
4411     ok (hchild != 0, "Failed to create child popup window\n");
4412     ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
4413     DestroyWindow(hchild);
4414
4415     /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
4416     flush_sequence();
4417     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
4418                              0, 0, 100, 100, hparent, 0, 0, NULL);
4419     ok (hchild != 0, "Failed to create popup window\n");
4420     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4421     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4422     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4423     flush_sequence();
4424     ShowWindow(hchild, SW_SHOW);
4425     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4426     flush_sequence();
4427     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4428     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4429     flush_sequence();
4430     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4431     ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
4432     DestroyWindow(hchild);
4433
4434     /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
4435      * changes nothing in message sequences.
4436      */
4437     flush_sequence();
4438     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
4439                              0, 0, 100, 100, hparent, 0, 0, NULL);
4440     ok (hchild != 0, "Failed to create popup window\n");
4441     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4442     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4443     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4444     flush_sequence();
4445     ShowWindow(hchild, SW_SHOW);
4446     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4447     flush_sequence();
4448     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4449     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4450     DestroyWindow(hchild);
4451
4452     flush_sequence();
4453     hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
4454                            0, 0, 100, 100, hparent, 0, 0, NULL);
4455     ok(hwnd != 0, "Failed to create custom dialog window\n");
4456     ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
4457
4458     /*
4459     trace("testing scroll APIs on a visible dialog %p\n", hwnd);
4460     test_scroll_messages(hwnd);
4461     */
4462
4463     flush_sequence();
4464
4465     test_def_id = 1;
4466     SendMessage(hwnd, WM_NULL, 0, 0);
4467
4468     flush_sequence();
4469     after_end_dialog = 1;
4470     EndDialog( hwnd, 0 );
4471     ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
4472
4473     DestroyWindow(hwnd);
4474     after_end_dialog = 0;
4475     test_def_id = 0;
4476
4477     hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP,
4478                            0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
4479     ok(hwnd != 0, "Failed to create custom dialog window\n");
4480     flush_sequence();
4481     trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
4482     ShowWindow(hwnd, SW_SHOW);
4483     ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
4484     DestroyWindow(hwnd);
4485
4486     flush_sequence();
4487     DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
4488     ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
4489
4490     DestroyWindow(hparent);
4491     flush_sequence();
4492
4493     /* Message sequence for SetMenu */
4494     ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a window without a menu\n");
4495     ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
4496
4497     hmenu = CreateMenu();
4498     ok (hmenu != 0, "Failed to create menu\n");
4499     ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
4500     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4501                            100, 100, 200, 200, 0, hmenu, 0, NULL);
4502     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4503     ok (SetMenu(hwnd, 0), "SetMenu\n");
4504     ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
4505     ok (SetMenu(hwnd, 0), "SetMenu\n");
4506     ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
4507     ShowWindow(hwnd, SW_SHOW);
4508     UpdateWindow( hwnd );
4509     flush_events();
4510     flush_sequence();
4511     ok (SetMenu(hwnd, 0), "SetMenu\n");
4512     ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
4513     ok (SetMenu(hwnd, hmenu), "SetMenu\n");
4514     ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
4515
4516     UpdateWindow( hwnd );
4517     flush_events();
4518     flush_sequence();
4519     ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
4520     flush_events();
4521     ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
4522
4523     DestroyWindow(hwnd);
4524     flush_sequence();
4525
4526     /* Message sequence for EnableWindow */
4527     hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4528                               100, 100, 200, 200, 0, 0, 0, NULL);
4529     ok (hparent != 0, "Failed to create parent window\n");
4530     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
4531                              0, 0, 10, 10, hparent, 0, 0, NULL);
4532     ok (hchild != 0, "Failed to create child window\n");
4533
4534     SetFocus(hchild);
4535     flush_events();
4536     flush_sequence();
4537
4538     EnableWindow(hparent, FALSE);
4539     ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
4540
4541     EnableWindow(hparent, TRUE);
4542     ok_sequence(WmEnableWindowSeq_2, "EnableWindow(TRUE)", FALSE);
4543
4544     flush_events();
4545     flush_sequence();
4546
4547     test_MsgWaitForMultipleObjects(hparent);
4548
4549     /* the following test causes an exception in user.exe under win9x */
4550     if (!PostMessageW( hparent, WM_USER, 0, 0 ))
4551     {
4552         DestroyWindow(hparent);
4553         flush_sequence();
4554         return;
4555     }
4556     PostMessageW( hparent, WM_USER+1, 0, 0 );
4557     /* PeekMessage(NULL) fails, but still removes the message */
4558     SetLastError(0xdeadbeef);
4559     ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
4560     ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
4561         GetLastError() == 0xdeadbeef, /* NT4 */
4562         "last error is %d\n", GetLastError() );
4563     ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
4564     ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
4565
4566     DestroyWindow(hchild);
4567     DestroyWindow(hparent);
4568     flush_sequence();
4569
4570     /* Message sequences for WM_SETICON */
4571     trace("testing WM_SETICON\n");
4572     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4573                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4574                            NULL, NULL, 0);
4575     ShowWindow(hwnd, SW_SHOW);
4576     UpdateWindow(hwnd);
4577     flush_events();
4578     flush_sequence();
4579     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4580     ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
4581
4582     ShowWindow(hwnd, SW_HIDE);
4583     flush_events();
4584     flush_sequence();
4585     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4586     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window with caption", FALSE);
4587     DestroyWindow(hwnd);
4588     flush_sequence();
4589
4590     hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
4591                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4592                            NULL, NULL, 0);
4593     ShowWindow(hwnd, SW_SHOW);
4594     UpdateWindow(hwnd);
4595     flush_events();
4596     flush_sequence();
4597     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4598     ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
4599
4600     ShowWindow(hwnd, SW_HIDE);
4601     flush_events();
4602     flush_sequence();
4603     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4604     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
4605
4606     flush_sequence();
4607     res = SendMessage(hwnd, 0x3B, 0x8000000b, 0);
4608     if (!res)
4609     {
4610         todo_wine win_skip( "Message 0x3b not supported\n" );
4611         goto done;
4612     }
4613     ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE);
4614     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %ld\n", res);
4615     res = SendMessage(hwnd, 0x3B, 0x0000000b, 0);
4616     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE);
4617     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %ld\n", res);
4618     res = SendMessage(hwnd, 0x3B, 0x0000000f, 0);
4619     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE);
4620     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %ld\n", res);
4621
4622     flush_sequence();
4623     res = SendMessage(hwnd, 0x3B, 0x80000008, 0);
4624     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE);
4625     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %ld\n", res);
4626     res = SendMessage(hwnd, 0x3B, 0x00000008, 0);
4627     ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE);
4628     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %ld\n", res);
4629
4630     res = SendMessage(hwnd, 0x3B, 0x80000004, 0);
4631     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE);
4632     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %ld\n", res);
4633
4634     res = SendMessage(hwnd, 0x3B, 0x80000001, 0);
4635     ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE);
4636     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %ld\n", res);
4637
4638 done:
4639     DestroyWindow(hwnd);
4640     flush_sequence();
4641 }
4642
4643 static void test_setwindowpos(void)
4644 {
4645     HWND hwnd;
4646     RECT rc;
4647     LRESULT res;
4648     const INT winX = 100;
4649     const INT winY = 100;
4650     const INT sysX = GetSystemMetrics(SM_CXMINTRACK);
4651
4652     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
4653                            0, 0, winX, winY, 0,
4654                            NULL, NULL, 0);
4655
4656     GetWindowRect(hwnd, &rc);
4657     expect(sysX, rc.right);
4658     expect(winY, rc.bottom);
4659
4660     flush_events();
4661     flush_sequence();
4662     res = SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, winX, winY, 0);
4663     ok_sequence(WmZOrder, "Z-Order", TRUE);
4664     ok(res == TRUE, "SetWindowPos expected TRUE, got %ld\n", res);
4665
4666     GetWindowRect(hwnd, &rc);
4667     expect(sysX, rc.right);
4668     expect(winY, rc.bottom);
4669     DestroyWindow(hwnd);
4670 }
4671
4672 static void invisible_parent_tests(void)
4673 {
4674     HWND hparent, hchild;
4675
4676     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
4677                               100, 100, 200, 200, 0, 0, 0, NULL);
4678     ok (hparent != 0, "Failed to create parent window\n");
4679     flush_sequence();
4680
4681     /* test showing child with hidden parent */
4682
4683     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4684                              0, 0, 10, 10, hparent, 0, 0, NULL);
4685     ok (hchild != 0, "Failed to create child window\n");
4686     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4687
4688     ShowWindow( hchild, SW_MINIMIZE );
4689     ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4690     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4691     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4692
4693     /* repeat */
4694     flush_events();
4695     flush_sequence();
4696     ShowWindow( hchild, SW_MINIMIZE );
4697     ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4698
4699     DestroyWindow(hchild);
4700     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4701                              0, 0, 10, 10, hparent, 0, 0, NULL);
4702     flush_sequence();
4703
4704     ShowWindow( hchild, SW_MAXIMIZE );
4705     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
4706     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4707     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4708
4709     /* repeat */
4710     flush_events();
4711     flush_sequence();
4712     ShowWindow( hchild, SW_MAXIMIZE );
4713     ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
4714
4715     DestroyWindow(hchild);
4716     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4717                              0, 0, 10, 10, hparent, 0, 0, NULL);
4718     flush_sequence();
4719
4720     ShowWindow( hchild, SW_RESTORE );
4721     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
4722     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4723     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4724
4725     DestroyWindow(hchild);
4726     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4727                              0, 0, 10, 10, hparent, 0, 0, NULL);
4728     flush_sequence();
4729
4730     ShowWindow( hchild, SW_SHOWMINIMIZED );
4731     ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
4732     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4733     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4734
4735     /* repeat */
4736     flush_events();
4737     flush_sequence();
4738     ShowWindow( hchild, SW_SHOWMINIMIZED );
4739     ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
4740
4741     DestroyWindow(hchild);
4742     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4743                              0, 0, 10, 10, hparent, 0, 0, NULL);
4744     flush_sequence();
4745
4746     /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
4747     ShowWindow( hchild, SW_SHOWMAXIMIZED );
4748     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
4749     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4750     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4751
4752     DestroyWindow(hchild);
4753     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4754                              0, 0, 10, 10, hparent, 0, 0, NULL);
4755     flush_sequence();
4756
4757     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
4758     ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
4759     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4760     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4761
4762     /* repeat */
4763     flush_events();
4764     flush_sequence();
4765     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
4766     ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
4767
4768     DestroyWindow(hchild);
4769     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4770                              0, 0, 10, 10, hparent, 0, 0, NULL);
4771     flush_sequence();
4772
4773     /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
4774     ShowWindow( hchild, SW_FORCEMINIMIZE );
4775     ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
4776 todo_wine {
4777     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
4778 }
4779     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4780
4781     DestroyWindow(hchild);
4782     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4783                              0, 0, 10, 10, hparent, 0, 0, NULL);
4784     flush_sequence();
4785
4786     ShowWindow( hchild, SW_SHOWNA );
4787     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
4788     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4789     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4790
4791     /* repeat */
4792     flush_events();
4793     flush_sequence();
4794     ShowWindow( hchild, SW_SHOWNA );
4795     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
4796
4797     DestroyWindow(hchild);
4798     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4799                              0, 0, 10, 10, hparent, 0, 0, NULL);
4800     flush_sequence();
4801
4802     ShowWindow( hchild, SW_SHOW );
4803     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
4804     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4805     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4806
4807     /* repeat */
4808     flush_events();
4809     flush_sequence();
4810     ShowWindow( hchild, SW_SHOW );
4811     ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
4812
4813     ShowWindow( hchild, SW_HIDE );
4814     ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
4815     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
4816     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4817
4818     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4819     ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
4820     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4821     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4822
4823     SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4824     ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
4825     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
4826     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4827
4828     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4829     flush_sequence();
4830     DestroyWindow(hchild);
4831     ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
4832
4833     DestroyWindow(hparent);
4834     flush_sequence();
4835 }
4836
4837 /****************** button message test *************************/
4838 static const struct message WmSetFocusButtonSeq[] =
4839 {
4840     { HCBT_SETFOCUS, hook },
4841     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
4842     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4843     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4844     { WM_SETFOCUS, sent|wparam, 0 },
4845     { WM_CTLCOLORBTN, sent|defwinproc },
4846     { 0 }
4847 };
4848 static const struct message WmKillFocusButtonSeq[] =
4849 {
4850     { HCBT_SETFOCUS, hook },
4851     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4852     { WM_KILLFOCUS, sent|wparam, 0 },
4853     { WM_CTLCOLORBTN, sent|defwinproc },
4854     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
4855     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
4856     { 0 }
4857 };
4858 static const struct message WmSetFocusStaticSeq[] =
4859 {
4860     { HCBT_SETFOCUS, hook },
4861     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
4862     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4863     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4864     { WM_SETFOCUS, sent|wparam, 0 },
4865     { WM_CTLCOLORSTATIC, sent|defwinproc },
4866     { 0 }
4867 };
4868 static const struct message WmKillFocusStaticSeq[] =
4869 {
4870     { HCBT_SETFOCUS, hook },
4871     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4872     { WM_KILLFOCUS, sent|wparam, 0 },
4873     { WM_CTLCOLORSTATIC, sent|defwinproc },
4874     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
4875     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
4876     { 0 }
4877 };
4878 static const struct message WmLButtonDownSeq[] =
4879 {
4880     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
4881     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
4882     { HCBT_SETFOCUS, hook },
4883     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
4884     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4885     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4886     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
4887     { WM_CTLCOLORBTN, sent|defwinproc },
4888     { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
4889     { WM_CTLCOLORBTN, sent|defwinproc },
4890     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4891     { 0 }
4892 };
4893 static const struct message WmLButtonUpSeq[] =
4894 {
4895     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
4896     { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
4897     { WM_CTLCOLORBTN, sent|defwinproc },
4898     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4899     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
4900     { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
4901     { 0 }
4902 };
4903 static const struct message WmSetFontButtonSeq[] =
4904 {
4905     { WM_SETFONT, sent },
4906     { WM_PAINT, sent },
4907     { WM_ERASEBKGND, sent|defwinproc|optional },
4908     { WM_CTLCOLORBTN, sent|defwinproc },
4909     { 0 }
4910 };
4911
4912 static WNDPROC old_button_proc;
4913
4914 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4915 {
4916     static long defwndproc_counter = 0;
4917     LRESULT ret;
4918     struct message msg;
4919
4920     trace("button: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
4921
4922     /* explicitly ignore WM_GETICON message */
4923     if (message == WM_GETICON) return 0;
4924
4925     /* ignore registered messages */
4926     if (message >= 0xc000) return 0;
4927
4928     msg.message = message;
4929     msg.flags = sent|wparam|lparam;
4930     if (defwndproc_counter) msg.flags |= defwinproc;
4931     msg.wParam = wParam;
4932     msg.lParam = lParam;
4933     add_message(&msg);
4934
4935     if (message == BM_SETSTATE)
4936         ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
4937
4938     defwndproc_counter++;
4939     ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
4940     defwndproc_counter--;
4941
4942     return ret;
4943 }
4944
4945 static void subclass_button(void)
4946 {
4947     WNDCLASSA cls;
4948
4949     if (!GetClassInfoA(0, "button", &cls)) assert(0);
4950
4951     old_button_proc = cls.lpfnWndProc;
4952
4953     cls.hInstance = GetModuleHandle(0);
4954     cls.lpfnWndProc = button_hook_proc;
4955     cls.lpszClassName = "my_button_class";
4956     UnregisterClass(cls.lpszClassName, cls.hInstance);
4957     if (!RegisterClassA(&cls)) assert(0);
4958 }
4959
4960 static void test_button_messages(void)
4961 {
4962     static const struct
4963     {
4964         DWORD style;
4965         DWORD dlg_code;
4966         const struct message *setfocus;
4967         const struct message *killfocus;
4968     } button[] = {
4969         { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
4970           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
4971         { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
4972           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
4973         { BS_CHECKBOX, DLGC_BUTTON,
4974           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4975         { BS_AUTOCHECKBOX, DLGC_BUTTON,
4976           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4977         { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
4978           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4979         { BS_3STATE, DLGC_BUTTON,
4980           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4981         { BS_AUTO3STATE, DLGC_BUTTON,
4982           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4983         { BS_GROUPBOX, DLGC_STATIC,
4984           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4985         { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
4986           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
4987         { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
4988           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4989         { BS_OWNERDRAW, DLGC_BUTTON,
4990           WmSetFocusButtonSeq, WmKillFocusButtonSeq }
4991     };
4992     unsigned int i;
4993     HWND hwnd;
4994     DWORD dlg_code;
4995     HFONT zfont;
4996
4997     subclass_button();
4998
4999     for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
5000     {
5001         hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP,
5002                                0, 0, 50, 14, 0, 0, 0, NULL);
5003         ok(hwnd != 0, "Failed to create button window\n");
5004
5005         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
5006         ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
5007
5008         ShowWindow(hwnd, SW_SHOW);
5009         UpdateWindow(hwnd);
5010         SetFocus(0);
5011         flush_sequence();
5012
5013         trace("button style %08x\n", button[i].style);
5014         SetFocus(hwnd);
5015         ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
5016
5017         SetFocus(0);
5018         ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
5019
5020         DestroyWindow(hwnd);
5021     }
5022
5023     hwnd = CreateWindowExA(0, "my_button_class", "test", BS_PUSHBUTTON | WS_POPUP | WS_VISIBLE,
5024                            0, 0, 50, 14, 0, 0, 0, NULL);
5025     ok(hwnd != 0, "Failed to create button window\n");
5026
5027     SetFocus(0);
5028     flush_events();
5029     flush_sequence();
5030
5031     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
5032     ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
5033
5034     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
5035     ok_sequence(WmLButtonUpSeq, "WM_LBUTTONUP on a button", FALSE);
5036
5037     flush_sequence();
5038     zfont = (HFONT)GetStockObject(SYSTEM_FONT);
5039     SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
5040     UpdateWindow(hwnd);
5041     ok_sequence(WmSetFontButtonSeq, "WM_SETFONT on a button", FALSE);
5042
5043     DestroyWindow(hwnd);
5044 }
5045
5046 /****************** static message test *************************/
5047 static const struct message WmSetFontStaticSeq[] =
5048 {
5049     { WM_SETFONT, sent },
5050     { WM_PAINT, sent|defwinproc },
5051     { WM_ERASEBKGND, sent|defwinproc|optional },
5052     { WM_CTLCOLORSTATIC, sent|defwinproc },
5053     { 0 }
5054 };
5055
5056 static WNDPROC old_static_proc;
5057
5058 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5059 {
5060     static long defwndproc_counter = 0;
5061     LRESULT ret;
5062     struct message msg;
5063
5064     trace("static: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
5065
5066     /* explicitly ignore WM_GETICON message */
5067     if (message == WM_GETICON) return 0;
5068
5069     /* ignore registered messages */
5070     if (message >= 0xc000) return 0;
5071
5072     msg.message = message;
5073     msg.flags = sent|wparam|lparam;
5074     if (defwndproc_counter) msg.flags |= defwinproc;
5075     msg.wParam = wParam;
5076     msg.lParam = lParam;
5077     add_message(&msg);
5078
5079     defwndproc_counter++;
5080     ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
5081     defwndproc_counter--;
5082
5083     return ret;
5084 }
5085
5086 static void subclass_static(void)
5087 {
5088     WNDCLASSA cls;
5089
5090     if (!GetClassInfoA(0, "static", &cls)) assert(0);
5091
5092     old_static_proc = cls.lpfnWndProc;
5093
5094     cls.hInstance = GetModuleHandle(0);
5095     cls.lpfnWndProc = static_hook_proc;
5096     cls.lpszClassName = "my_static_class";
5097     UnregisterClass(cls.lpszClassName, cls.hInstance);
5098     if (!RegisterClassA(&cls)) assert(0);
5099 }
5100
5101 static void test_static_messages(void)
5102 {
5103     /* FIXME: make as comprehensive as the button message test */
5104     static const struct
5105     {
5106         DWORD style;
5107         DWORD dlg_code;
5108         const struct message *setfont;
5109     } static_ctrl[] = {
5110         { SS_LEFT, DLGC_STATIC,
5111           WmSetFontStaticSeq }
5112     };
5113     unsigned int i;
5114     HWND hwnd;
5115     DWORD dlg_code;
5116
5117     subclass_static();
5118
5119     for (i = 0; i < sizeof(static_ctrl)/sizeof(static_ctrl[0]); i++)
5120     {
5121         hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
5122                                0, 0, 50, 14, 0, 0, 0, NULL);
5123         ok(hwnd != 0, "Failed to create static window\n");
5124
5125         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
5126         ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
5127
5128         ShowWindow(hwnd, SW_SHOW);
5129         UpdateWindow(hwnd);
5130         SetFocus(0);
5131         flush_sequence();
5132
5133         trace("static style %08x\n", static_ctrl[i].style);
5134         SendMessage(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
5135         ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
5136
5137         DestroyWindow(hwnd);
5138     }
5139 }
5140
5141 /****************** ComboBox message test *************************/
5142 #define ID_COMBOBOX 0x000f
5143
5144 static const struct message WmKeyDownComboSeq[] =
5145 {
5146     { WM_KEYDOWN, sent|wparam|lparam, VK_DOWN, 0 },
5147     { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(1000, LBN_SELCHANGE) },
5148     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDOK) },
5149     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELCHANGE) },
5150     { WM_CTLCOLOREDIT, sent|parent },
5151     { WM_KEYUP, sent|wparam|lparam, VK_DOWN, 0 },
5152     { 0 }
5153 };
5154
5155 static WNDPROC old_combobox_proc;
5156
5157 static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5158 {
5159     static long defwndproc_counter = 0;
5160     LRESULT ret;
5161     struct message msg;
5162
5163     /* do not log painting messages */
5164     if (message != WM_PAINT &&
5165         message != WM_NCPAINT &&
5166         message != WM_SYNCPAINT &&
5167         message != WM_ERASEBKGND &&
5168         message != WM_NCHITTEST &&
5169         message != WM_GETTEXT &&
5170         message != WM_GETICON &&
5171         message != WM_DEVICECHANGE)
5172     {
5173         trace("combo: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
5174
5175         msg.message = message;
5176         msg.flags = sent|wparam|lparam;
5177         if (defwndproc_counter) msg.flags |= defwinproc;
5178         msg.wParam = wParam;
5179         msg.lParam = lParam;
5180         add_message(&msg);
5181     }
5182
5183     defwndproc_counter++;
5184     ret = CallWindowProcA(old_combobox_proc, hwnd, message, wParam, lParam);
5185     defwndproc_counter--;
5186
5187     return ret;
5188 }
5189
5190 static void subclass_combobox(void)
5191 {
5192     WNDCLASSA cls;
5193
5194     if (!GetClassInfoA(0, "ComboBox", &cls)) assert(0);
5195
5196     old_combobox_proc = cls.lpfnWndProc;
5197
5198     cls.hInstance = GetModuleHandle(0);
5199     cls.lpfnWndProc = combobox_hook_proc;
5200     cls.lpszClassName = "my_combobox_class";
5201     UnregisterClass(cls.lpszClassName, cls.hInstance);
5202     if (!RegisterClassA(&cls)) assert(0);
5203 }
5204
5205 static void test_combobox_messages(void)
5206 {
5207     HWND parent, combo;
5208     LRESULT ret;
5209
5210     subclass_combobox();
5211
5212     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5213                              100, 100, 200, 200, 0, 0, 0, NULL);
5214     ok(parent != 0, "Failed to create parent window\n");
5215     flush_sequence();
5216
5217     combo = CreateWindowEx(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
5218                            0, 0, 100, 150, parent, (HMENU)ID_COMBOBOX, 0, NULL);
5219     ok(combo != 0, "Failed to create combobox window\n");
5220
5221     UpdateWindow(combo);
5222
5223     ret = SendMessage(combo, WM_GETDLGCODE, 0, 0);
5224     ok(ret == (DLGC_WANTCHARS | DLGC_WANTARROWS), "wrong dlg_code %08lx\n", ret);
5225
5226     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
5227     ok(ret == 0, "expected 0, got %ld\n", ret);
5228     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 1");
5229     ok(ret == 1, "expected 1, got %ld\n", ret);
5230     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 2");
5231     ok(ret == 2, "expected 2, got %ld\n", ret);
5232
5233     SendMessage(combo, CB_SETCURSEL, 0, 0);
5234     SetFocus(combo);
5235     flush_sequence();
5236
5237     log_all_parent_messages++;
5238     SendMessage(combo, WM_KEYDOWN, VK_DOWN, 0);
5239     SendMessage(combo, WM_KEYUP, VK_DOWN, 0);
5240     log_all_parent_messages--;
5241     ok_sequence(WmKeyDownComboSeq, "WM_KEYDOWN/VK_DOWN on a ComboBox", FALSE);
5242
5243     DestroyWindow(combo);
5244     DestroyWindow(parent);
5245 }
5246
5247 /****************** WM_IME_KEYDOWN message test *******************/
5248
5249 static const struct message WmImeKeydownMsgSeq_0[] =
5250 {
5251     { WM_IME_KEYDOWN, wparam, VK_RETURN },
5252     { WM_CHAR, wparam, 'A' },
5253     { 0 }
5254 };
5255
5256 static const struct message WmImeKeydownMsgSeq_1[] =
5257 {
5258     { WM_KEYDOWN, optional|wparam, VK_RETURN },
5259     { WM_CHAR,    optional|wparam, VK_RETURN },
5260     { 0 }
5261 };
5262
5263 static LRESULT WINAPI wmime_keydown_procA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5264 {
5265     struct message msg;
5266
5267     trace("wmime_keydown_procA: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
5268
5269     msg.message = message;
5270     msg.flags = wparam|lparam;
5271     msg.wParam = wParam;
5272     msg.lParam = lParam;
5273     add_message(&msg);
5274
5275     return DefWindowProcA(hwnd, message, wParam, lParam);
5276 }
5277
5278 static void register_wmime_keydown_class(void)
5279 {
5280     WNDCLASSA cls;
5281
5282     ZeroMemory(&cls, sizeof(WNDCLASSA));
5283     cls.lpfnWndProc = wmime_keydown_procA;
5284     cls.hInstance = GetModuleHandleA(0);
5285     cls.lpszClassName = "wmime_keydown_class";
5286     if (!RegisterClassA(&cls)) assert(0);
5287 }
5288
5289 void test_wmime_keydown_message(void)
5290 {
5291     HWND hwnd;
5292     MSG msg;
5293
5294     trace("Message sequences by WM_IME_KEYDOWN\n");
5295
5296     register_wmime_keydown_class();
5297     hwnd = CreateWindowExA(0, "wmime_keydown_class", NULL, WS_OVERLAPPEDWINDOW,
5298                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5299                            NULL, NULL, 0);
5300     flush_events();
5301     flush_sequence();
5302
5303     SendMessage(hwnd, WM_IME_KEYDOWN, VK_RETURN, 0x1c0001);
5304     SendMessage(hwnd, WM_CHAR, 'A', 1);
5305     ok_sequence(WmImeKeydownMsgSeq_0, "WM_IME_KEYDOWN 0", FALSE);
5306
5307     while ( PeekMessage(&msg, 0, 0, 0, PM_REMOVE) )
5308     {
5309         TranslateMessage(&msg);
5310         DispatchMessage(&msg);
5311     }
5312     ok_sequence(WmImeKeydownMsgSeq_1, "WM_IME_KEYDOWN 1", FALSE);
5313
5314     DestroyWindow(hwnd);
5315 }
5316
5317 /************* painting message test ********************/
5318
5319 void dump_region(HRGN hrgn)
5320 {
5321     DWORD i, size;
5322     RGNDATA *data = NULL;
5323     RECT *rect;
5324
5325     if (!hrgn)
5326     {
5327         printf( "null region\n" );
5328         return;
5329     }
5330     if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
5331     if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
5332     GetRegionData( hrgn, size, data );
5333     printf("%d rects:", data->rdh.nCount );
5334     for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
5335         printf( " (%d,%d)-(%d,%d)", rect->left, rect->top, rect->right, rect->bottom );
5336     printf("\n");
5337     HeapFree( GetProcessHeap(), 0, data );
5338 }
5339
5340 static void check_update_rgn( HWND hwnd, HRGN hrgn )
5341 {
5342     INT ret;
5343     RECT r1, r2;
5344     HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
5345     HRGN update = CreateRectRgn( 0, 0, 0, 0 );
5346
5347     ret = GetUpdateRgn( hwnd, update, FALSE );
5348     ok( ret != ERROR, "GetUpdateRgn failed\n" );
5349     if (ret == NULLREGION)
5350     {
5351         ok( !hrgn, "Update region shouldn't be empty\n" );
5352     }
5353     else
5354     {
5355         if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
5356         {
5357             ok( 0, "Regions are different\n" );
5358             if (winetest_debug > 0)
5359             {
5360                 printf( "Update region: " );
5361                 dump_region( update );
5362                 printf( "Wanted region: " );
5363                 dump_region( hrgn );
5364             }
5365         }
5366     }
5367     GetRgnBox( update, &r1 );
5368     GetUpdateRect( hwnd, &r2, FALSE );
5369     ok( r1.left == r2.left && r1.top == r2.top && r1.right == r2.right && r1.bottom == r2.bottom,
5370         "Rectangles are different: %d,%d-%d,%d / %d,%d-%d,%d\n",
5371         r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom );
5372
5373     DeleteObject( tmp );
5374     DeleteObject( update );
5375 }
5376
5377 static const struct message WmInvalidateRgn[] = {
5378     { WM_NCPAINT, sent },
5379     { WM_GETTEXT, sent|defwinproc|optional },
5380     { 0 }
5381 };
5382
5383 static const struct message WmGetUpdateRect[] = {
5384     { WM_NCPAINT, sent },
5385     { WM_GETTEXT, sent|defwinproc|optional },
5386     { WM_PAINT, sent },
5387     { 0 }
5388 };
5389
5390 static const struct message WmInvalidateFull[] = {
5391     { WM_NCPAINT, sent|wparam, 1 },
5392     { WM_GETTEXT, sent|defwinproc|optional },
5393     { 0 }
5394 };
5395
5396 static const struct message WmInvalidateErase[] = {
5397     { WM_NCPAINT, sent|wparam, 1 },
5398     { WM_GETTEXT, sent|defwinproc|optional },
5399     { WM_ERASEBKGND, sent },
5400     { 0 }
5401 };
5402
5403 static const struct message WmInvalidatePaint[] = {
5404     { WM_PAINT, sent },
5405     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
5406     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5407     { 0 }
5408 };
5409
5410 static const struct message WmInvalidateErasePaint[] = {
5411     { WM_PAINT, sent },
5412     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
5413     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5414     { WM_ERASEBKGND, sent|beginpaint },
5415     { 0 }
5416 };
5417
5418 static const struct message WmInvalidateErasePaint2[] = {
5419     { WM_PAINT, sent },
5420     { WM_NCPAINT, sent|beginpaint },
5421     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5422     { WM_ERASEBKGND, sent|beginpaint },
5423     { 0 }
5424 };
5425
5426 static const struct message WmErase[] = {
5427     { WM_ERASEBKGND, sent },
5428     { 0 }
5429 };
5430
5431 static const struct message WmPaint[] = {
5432     { WM_PAINT, sent },
5433     { 0 }
5434 };
5435
5436 static const struct message WmParentOnlyPaint[] = {
5437     { WM_PAINT, sent|parent },
5438     { 0 }
5439 };
5440
5441 static const struct message WmInvalidateParent[] = {
5442     { WM_NCPAINT, sent|parent },
5443     { WM_GETTEXT, sent|defwinproc|parent|optional },
5444     { WM_ERASEBKGND, sent|parent },
5445     { 0 }
5446 };
5447
5448 static const struct message WmInvalidateParentChild[] = {
5449     { WM_NCPAINT, sent|parent },
5450     { WM_GETTEXT, sent|defwinproc|parent|optional },
5451     { WM_ERASEBKGND, sent|parent },
5452     { WM_NCPAINT, sent },
5453     { WM_GETTEXT, sent|defwinproc|optional },
5454     { WM_ERASEBKGND, sent },
5455     { 0 }
5456 };
5457
5458 static const struct message WmInvalidateParentChild2[] = {
5459     { WM_ERASEBKGND, sent|parent },
5460     { WM_NCPAINT, sent },
5461     { WM_GETTEXT, sent|defwinproc|optional },
5462     { WM_ERASEBKGND, sent },
5463     { 0 }
5464 };
5465
5466 static const struct message WmParentPaint[] = {
5467     { WM_PAINT, sent|parent },
5468     { WM_PAINT, sent },
5469     { 0 }
5470 };
5471
5472 static const struct message WmParentPaintNc[] = {
5473     { WM_PAINT, sent|parent },
5474     { WM_PAINT, sent },
5475     { WM_NCPAINT, sent|beginpaint },
5476     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5477     { WM_ERASEBKGND, sent|beginpaint },
5478     { 0 }
5479 };
5480
5481 static const struct message WmChildPaintNc[] = {
5482     { WM_PAINT, sent },
5483     { WM_NCPAINT, sent|beginpaint },
5484     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5485     { WM_ERASEBKGND, sent|beginpaint },
5486     { 0 }
5487 };
5488
5489 static const struct message WmParentErasePaint[] = {
5490     { WM_PAINT, sent|parent },
5491     { WM_NCPAINT, sent|parent|beginpaint },
5492     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
5493     { WM_ERASEBKGND, sent|parent|beginpaint },
5494     { WM_PAINT, sent },
5495     { WM_NCPAINT, sent|beginpaint },
5496     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5497     { WM_ERASEBKGND, sent|beginpaint },
5498     { 0 }
5499 };
5500
5501 static const struct message WmParentOnlyNcPaint[] = {
5502     { WM_PAINT, sent|parent },
5503     { WM_NCPAINT, sent|parent|beginpaint },
5504     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
5505     { 0 }
5506 };
5507
5508 static const struct message WmSetParentStyle[] = {
5509     { WM_STYLECHANGING, sent|parent },
5510     { WM_STYLECHANGED, sent|parent },
5511     { 0 }
5512 };
5513
5514 static void test_paint_messages(void)
5515 {
5516     BOOL ret;
5517     RECT rect;
5518     POINT pt;
5519     MSG msg;
5520     HWND hparent, hchild;
5521     HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
5522     HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
5523     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5524                                 100, 100, 200, 200, 0, 0, 0, NULL);
5525     ok (hwnd != 0, "Failed to create overlapped window\n");
5526
5527     ShowWindow( hwnd, SW_SHOW );
5528     UpdateWindow( hwnd );
5529     flush_events();
5530     flush_sequence();
5531
5532     check_update_rgn( hwnd, 0 );
5533     SetRectRgn( hrgn, 10, 10, 20, 20 );
5534     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5535     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5536     check_update_rgn( hwnd, hrgn );
5537     SetRectRgn( hrgn2, 20, 20, 30, 30 );
5538     ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
5539     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5540     CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
5541     check_update_rgn( hwnd, hrgn );
5542     /* validate everything */
5543     ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5544     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5545     check_update_rgn( hwnd, 0 );
5546
5547     /* test empty region */
5548     SetRectRgn( hrgn, 10, 10, 10, 15 );
5549     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5550     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5551     check_update_rgn( hwnd, 0 );
5552     /* test empty rect */
5553     SetRect( &rect, 10, 10, 10, 15 );
5554     ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
5555     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5556     check_update_rgn( hwnd, 0 );
5557
5558     /* flush pending messages */
5559     flush_events();
5560     flush_sequence();
5561
5562     GetClientRect( hwnd, &rect );
5563     SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
5564     /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
5565      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
5566      */
5567     trace("testing InvalidateRect(0, NULL, FALSE)\n");
5568     SetRectEmpty( &rect );
5569     ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) should fail\n");
5570     check_update_rgn( hwnd, hrgn );
5571     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5572     flush_events();
5573     ok_sequence( WmPaint, "Paint", FALSE );
5574     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5575     check_update_rgn( hwnd, 0 );
5576
5577     /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
5578      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
5579      */
5580     trace("testing ValidateRect(0, NULL)\n");
5581     SetRectEmpty( &rect );
5582     ok(ValidateRect(0, &rect), "ValidateRect(0, &rc) should not fail\n");
5583     check_update_rgn( hwnd, hrgn );
5584     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5585     flush_events();
5586     ok_sequence( WmPaint, "Paint", FALSE );
5587     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5588     check_update_rgn( hwnd, 0 );
5589
5590     trace("testing InvalidateRgn(0, NULL, FALSE)\n");
5591     SetLastError(0xdeadbeef);
5592     ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
5593     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef,
5594        "wrong error code %d\n", GetLastError());
5595     check_update_rgn( hwnd, 0 );
5596     flush_events();
5597     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
5598
5599     trace("testing ValidateRgn(0, NULL)\n");
5600     SetLastError(0xdeadbeef);
5601     ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
5602     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error code %d\n", GetLastError());
5603     check_update_rgn( hwnd, 0 );
5604     flush_events();
5605     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
5606
5607     /* now with frame */
5608     SetRectRgn( hrgn, -5, -5, 20, 20 );
5609
5610     /* flush pending messages */
5611     flush_events();
5612     flush_sequence();
5613     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5614     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
5615
5616     SetRectRgn( hrgn, 0, 0, 20, 20 );  /* GetUpdateRgn clips to client area */
5617     check_update_rgn( hwnd, hrgn );
5618
5619     flush_sequence();
5620     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
5621     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
5622
5623     flush_sequence();
5624     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
5625     ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
5626
5627     GetClientRect( hwnd, &rect );
5628     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
5629     check_update_rgn( hwnd, hrgn );
5630
5631     flush_sequence();
5632     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
5633     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5634
5635     flush_sequence();
5636     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
5637     ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
5638     check_update_rgn( hwnd, 0 );
5639
5640     flush_sequence();
5641     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
5642     ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
5643     check_update_rgn( hwnd, 0 );
5644
5645     flush_sequence();
5646     SetRectRgn( hrgn, 0, 0, 100, 100 );
5647     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5648     SetRectRgn( hrgn, 0, 0, 50, 100 );
5649     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
5650     SetRectRgn( hrgn, 50, 0, 100, 100 );
5651     check_update_rgn( hwnd, hrgn );
5652     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
5653     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );  /* must not generate messages, everything is valid */
5654     check_update_rgn( hwnd, 0 );
5655
5656     flush_sequence();
5657     SetRectRgn( hrgn, 0, 0, 100, 100 );
5658     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
5659     SetRectRgn( hrgn, 0, 0, 100, 50 );
5660     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
5661     ok_sequence( WmErase, "Erase", FALSE );
5662     SetRectRgn( hrgn, 0, 50, 100, 100 );
5663     check_update_rgn( hwnd, hrgn );
5664
5665     flush_sequence();
5666     SetRectRgn( hrgn, 0, 0, 100, 100 );
5667     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
5668     SetRectRgn( hrgn, 0, 0, 50, 50 );
5669     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
5670     ok_sequence( WmPaint, "Paint", FALSE );
5671
5672     flush_sequence();
5673     SetRectRgn( hrgn, -4, -4, -2, -2 );
5674     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5675     SetRectRgn( hrgn, -200, -200, -198, -198 );
5676     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
5677     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
5678
5679     flush_sequence();
5680     SetRectRgn( hrgn, -4, -4, -2, -2 );
5681     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5682     SetRectRgn( hrgn, -4, -4, -3, -3 );
5683     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
5684     SetRectRgn( hrgn, 0, 0, 1, 1 );
5685     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
5686     ok_sequence( WmPaint, "Paint", FALSE );
5687
5688     flush_sequence();
5689     SetRectRgn( hrgn, -4, -4, -1, -1 );
5690     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5691     RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
5692     /* make sure no WM_PAINT was generated */
5693     flush_events();
5694     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
5695
5696     flush_sequence();
5697     SetRectRgn( hrgn, -4, -4, -1, -1 );
5698     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5699     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
5700     {
5701         if (msg.hwnd == hwnd && msg.message == WM_PAINT)
5702         {
5703             /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
5704             INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
5705             ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
5706             ret = GetUpdateRect( hwnd, &rect, FALSE );
5707             ok( ret, "Invalid GetUpdateRect result %d\n", ret );
5708             /* this will send WM_NCPAINT and validate the non client area */
5709             ret = GetUpdateRect( hwnd, &rect, TRUE );
5710             ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
5711         }
5712         DispatchMessage( &msg );
5713     }
5714     ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
5715
5716     DestroyWindow( hwnd );
5717
5718     /* now test with a child window */
5719
5720     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
5721                               100, 100, 200, 200, 0, 0, 0, NULL);
5722     ok (hparent != 0, "Failed to create parent window\n");
5723
5724     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
5725                            10, 10, 100, 100, hparent, 0, 0, NULL);
5726     ok (hchild != 0, "Failed to create child window\n");
5727
5728     ShowWindow( hparent, SW_SHOW );
5729     UpdateWindow( hparent );
5730     UpdateWindow( hchild );
5731     flush_events();
5732     flush_sequence();
5733     log_all_parent_messages++;
5734
5735     SetRect( &rect, 0, 0, 50, 50 );
5736     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5737     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
5738     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
5739
5740     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5741     pt.x = pt.y = 0;
5742     MapWindowPoints( hchild, hparent, &pt, 1 );
5743     SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
5744     check_update_rgn( hchild, hrgn );
5745     SetRectRgn( hrgn, 0, 0, 50, 50 );
5746     check_update_rgn( hparent, hrgn );
5747     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5748     ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
5749     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
5750     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
5751
5752     flush_events();
5753     ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
5754
5755     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
5756     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5757     ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
5758     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
5759     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
5760
5761     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
5762     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
5763     ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
5764
5765     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
5766     flush_sequence();
5767     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
5768     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5769     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
5770
5771     /* flush all paint messages */
5772     flush_events();
5773     flush_sequence();
5774
5775     /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
5776     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
5777     SetRectRgn( hrgn, 0, 0, 50, 50 );
5778     check_update_rgn( hparent, hrgn );
5779     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
5780     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5781     SetRectRgn( hrgn, 0, 0, 50, 50 );
5782     check_update_rgn( hparent, hrgn );
5783
5784     /* flush all paint messages */
5785     flush_events();
5786     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
5787     flush_sequence();
5788
5789     /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
5790     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5791     SetRectRgn( hrgn, 0, 0, 50, 50 );
5792     check_update_rgn( hparent, hrgn );
5793     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
5794     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5795     SetRectRgn( hrgn2, 10, 10, 50, 50 );
5796     CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
5797     check_update_rgn( hparent, hrgn );
5798     /* flush all paint messages */
5799     flush_events();
5800     flush_sequence();
5801
5802     /* same as above but parent gets completely validated */
5803     SetRect( &rect, 20, 20, 30, 30 );
5804     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5805     SetRectRgn( hrgn, 20, 20, 30, 30 );
5806     check_update_rgn( hparent, hrgn );
5807     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
5808     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5809     check_update_rgn( hparent, 0 );  /* no update region */
5810     flush_events();
5811     ok_sequence( WmEmptySeq, "WmEmpty", FALSE );  /* and no paint messages */
5812
5813     /* make sure RDW_VALIDATE on child doesn't have the same effect */
5814     flush_sequence();
5815     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5816     SetRectRgn( hrgn, 20, 20, 30, 30 );
5817     check_update_rgn( hparent, hrgn );
5818     RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
5819     SetRectRgn( hrgn, 20, 20, 30, 30 );
5820     check_update_rgn( hparent, hrgn );
5821
5822     /* same as above but normal WM_PAINT doesn't validate parent */
5823     flush_sequence();
5824     SetRect( &rect, 20, 20, 30, 30 );
5825     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5826     SetRectRgn( hrgn, 20, 20, 30, 30 );
5827     check_update_rgn( hparent, hrgn );
5828     /* no WM_PAINT in child while parent still pending */
5829     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5830     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
5831     while (PeekMessage( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5832     ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
5833
5834     flush_sequence();
5835     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5836     /* no WM_PAINT in child while parent still pending */
5837     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5838     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
5839     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
5840     /* now that parent is valid child should get WM_PAINT */
5841     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5842     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5843     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5844     ok_sequence( WmEmptySeq, "No other message", FALSE );
5845
5846     /* same thing with WS_CLIPCHILDREN in parent */
5847     flush_sequence();
5848     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
5849     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
5850     /* changing style invalidates non client area, but we need to invalidate something else to see it */
5851     RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
5852     ok_sequence( WmEmptySeq, "No message", FALSE );
5853     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
5854     ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
5855
5856     flush_sequence();
5857     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
5858     SetRectRgn( hrgn, 20, 20, 30, 30 );
5859     check_update_rgn( hparent, hrgn );
5860     /* no WM_PAINT in child while parent still pending */
5861     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5862     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
5863     /* WM_PAINT in parent first */
5864     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5865     ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
5866
5867     /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
5868     flush_sequence();
5869     SetRect( &rect, 0, 0, 30, 30 );
5870     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
5871     SetRectRgn( hrgn, 0, 0, 30, 30 );
5872     check_update_rgn( hparent, hrgn );
5873     flush_events();
5874     ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
5875
5876     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
5877     flush_sequence();
5878     SetRect( &rect, -10, 0, 30, 30 );
5879     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
5880     SetRect( &rect, 0, 0, 20, 20 );
5881     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
5882     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
5883     ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
5884
5885     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
5886     flush_sequence();
5887     SetRect( &rect, -10, 0, 30, 30 );
5888     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
5889     SetRect( &rect, 0, 0, 100, 100 );
5890     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
5891     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
5892     ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
5893     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5894     ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
5895
5896     /* test RDW_INTERNALPAINT behavior */
5897
5898     flush_sequence();
5899     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
5900     flush_events();
5901     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
5902
5903     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
5904     flush_events();
5905     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
5906
5907     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
5908     flush_events();
5909     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
5910
5911     assert( GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
5912     UpdateWindow( hparent );
5913     flush_events();
5914     flush_sequence();
5915     trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
5916     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5917     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
5918                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5919     flush_events();
5920     ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
5921
5922     UpdateWindow( hparent );
5923     flush_events();
5924     flush_sequence();
5925     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
5926     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5927     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
5928                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5929     flush_events();
5930     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
5931
5932     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
5933     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
5934     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
5935     flush_events();
5936     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
5937
5938     assert( !(GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
5939     UpdateWindow( hparent );
5940     flush_events();
5941     flush_sequence();
5942     trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
5943     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5944     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
5945                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5946     flush_events();
5947     ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
5948
5949     UpdateWindow( hparent );
5950     flush_events();
5951     flush_sequence();
5952     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
5953     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5954     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
5955                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5956     flush_events();
5957     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
5958
5959     ok(GetWindowLong( hparent, GWL_STYLE ) & WS_VISIBLE, "parent should be visible\n");
5960     ok(GetWindowLong( hchild, GWL_STYLE ) & WS_VISIBLE, "child should be visible\n");
5961
5962     UpdateWindow( hparent );
5963     flush_events();
5964     flush_sequence();
5965     trace("testing SetWindowPos(-10000, -10000) on child\n");
5966     SetWindowPos( hchild, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
5967     check_update_rgn( hchild, 0 );
5968     flush_events();
5969
5970 #if 0 /* this one doesn't pass under Wine yet */
5971     UpdateWindow( hparent );
5972     flush_events();
5973     flush_sequence();
5974     trace("testing ShowWindow(SW_MINIMIZE) on child\n");
5975     ShowWindow( hchild, SW_MINIMIZE );
5976     check_update_rgn( hchild, 0 );
5977     flush_events();
5978 #endif
5979
5980     UpdateWindow( hparent );
5981     flush_events();
5982     flush_sequence();
5983     trace("testing SetWindowPos(-10000, -10000) on parent\n");
5984     SetWindowPos( hparent, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
5985     check_update_rgn( hparent, 0 );
5986     flush_events();
5987
5988     log_all_parent_messages--;
5989     DestroyWindow( hparent );
5990     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
5991
5992     /* tests for moving windows off-screen (needs simple WS_POPUP windows) */
5993
5994     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_POPUP | WS_VISIBLE,
5995                               100, 100, 200, 200, 0, 0, 0, NULL);
5996     ok (hparent != 0, "Failed to create parent window\n");
5997
5998     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5999                            10, 10, 100, 100, hparent, 0, 0, NULL);
6000     ok (hchild != 0, "Failed to create child window\n");
6001
6002     ShowWindow( hparent, SW_SHOW );
6003     UpdateWindow( hparent );
6004     UpdateWindow( hchild );
6005     flush_events();
6006     flush_sequence();
6007
6008     /* moving child outside of parent boundaries changes update region */
6009     SetRect( &rect, 0, 0, 40, 40 );
6010     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6011     SetRectRgn( hrgn, 0, 0, 40, 40 );
6012     check_update_rgn( hchild, hrgn );
6013     MoveWindow( hchild, -10, 10, 100, 100, FALSE );
6014     SetRectRgn( hrgn, 10, 0, 40, 40 );
6015     check_update_rgn( hchild, hrgn );
6016     MoveWindow( hchild, -10, -10, 100, 100, FALSE );
6017     SetRectRgn( hrgn, 10, 10, 40, 40 );
6018     check_update_rgn( hchild, hrgn );
6019
6020     /* moving parent off-screen does too */
6021     SetRect( &rect, 0, 0, 100, 100 );
6022     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
6023     SetRectRgn( hrgn, 0, 0, 100, 100 );
6024     check_update_rgn( hparent, hrgn );
6025     SetRectRgn( hrgn, 10, 10, 40, 40 );
6026     check_update_rgn( hchild, hrgn );
6027     MoveWindow( hparent, -20, -20, 200, 200, FALSE );
6028     SetRectRgn( hrgn, 20, 20, 100, 100 );
6029     check_update_rgn( hparent, hrgn );
6030     SetRectRgn( hrgn, 30, 30, 40, 40 );
6031     check_update_rgn( hchild, hrgn );
6032
6033     /* invalidated region is cropped by the parent rects */
6034     SetRect( &rect, 0, 0, 50, 50 );
6035     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6036     SetRectRgn( hrgn, 30, 30, 50, 50 );
6037     check_update_rgn( hchild, hrgn );
6038
6039     DestroyWindow( hparent );
6040     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
6041     flush_sequence();
6042
6043     DeleteObject( hrgn );
6044     DeleteObject( hrgn2 );
6045 }
6046
6047 struct wnd_event
6048 {
6049     HWND hwnd;
6050     HANDLE event;
6051 };
6052
6053 static DWORD WINAPI thread_proc(void *param)
6054 {
6055     MSG msg;
6056     struct wnd_event *wnd_event = (struct wnd_event *)param;
6057
6058     wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
6059                                       100, 100, 200, 200, 0, 0, 0, NULL);
6060     ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
6061
6062     SetEvent(wnd_event->event);
6063
6064     while (GetMessage(&msg, 0, 0, 0))
6065     {
6066         TranslateMessage(&msg);
6067         DispatchMessage(&msg);
6068     }
6069
6070     ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
6071
6072     return 0;
6073 }
6074
6075 static void test_interthread_messages(void)
6076 {
6077     HANDLE hThread;
6078     DWORD tid;
6079     WNDPROC proc;
6080     MSG msg;
6081     char buf[256];
6082     int len, expected_len;
6083     struct wnd_event wnd_event;
6084     BOOL ret;
6085
6086     wnd_event.event = CreateEventW(NULL, 0, 0, NULL);
6087     if (!wnd_event.event)
6088     {
6089         trace("skipping interthread message test under win9x\n");
6090         return;
6091     }
6092
6093     hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
6094     ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
6095
6096     ok(WaitForSingleObject(wnd_event.event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6097
6098     CloseHandle(wnd_event.event);
6099
6100     SetLastError(0xdeadbeef);
6101     ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeded\n");
6102     ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == 0xdeadbeef,
6103        "wrong error code %d\n", GetLastError());
6104
6105     proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
6106     ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %d\n", GetLastError());
6107
6108     expected_len = lstrlenA("window caption text");
6109     memset(buf, 0, sizeof(buf));
6110     SetLastError(0xdeadbeef);
6111     len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
6112     ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %d, len %d, expected len %d\n", GetLastError(), len, expected_len);
6113     ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
6114
6115     msg.hwnd = wnd_event.hwnd;
6116     msg.message = WM_GETTEXT;
6117     msg.wParam = sizeof(buf);
6118     msg.lParam = (LPARAM)buf;
6119     memset(buf, 0, sizeof(buf));
6120     SetLastError(0xdeadbeef);
6121     len = DispatchMessageA(&msg);
6122     ok((!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY) || broken(len), /* nt4 */
6123        "DispatchMessageA(WM_GETTEXT) succeded on another thread window: ret %d, error %d\n", len, GetLastError());
6124
6125     /* the following test causes an exception in user.exe under win9x */
6126     msg.hwnd = wnd_event.hwnd;
6127     msg.message = WM_TIMER;
6128     msg.wParam = 0;
6129     msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
6130     SetLastError(0xdeadbeef);
6131     len = DispatchMessageA(&msg);
6132     ok(!len && GetLastError() == 0xdeadbeef,
6133        "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %d\n", len, GetLastError());
6134
6135     ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
6136     ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
6137
6138     ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6139     CloseHandle(hThread);
6140
6141     ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
6142 }
6143
6144
6145 static const struct message WmVkN[] = {
6146     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6147     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6148     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6149     { WM_CHAR, wparam|lparam, 'n', 1 },
6150     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
6151     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6152     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6153     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6154     { 0 }
6155 };
6156 static const struct message WmShiftVkN[] = {
6157     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
6158     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
6159     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
6160     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6161     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6162     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6163     { WM_CHAR, wparam|lparam, 'N', 1 },
6164     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
6165     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6166     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6167     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6168     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
6169     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
6170     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
6171     { 0 }
6172 };
6173 static const struct message WmCtrlVkN[] = {
6174     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6175     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6176     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6177     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6178     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6179     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6180     { WM_CHAR, wparam|lparam, 0x000e, 1 },
6181     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
6182     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6183     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6184     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6185     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6186     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6187     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6188     { 0 }
6189 };
6190 static const struct message WmCtrlVkN_2[] = {
6191     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6192     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6193     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6194     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6195     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6196     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
6197     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6198     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6199     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6200     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6201     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6202     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6203     { 0 }
6204 };
6205 static const struct message WmAltVkN[] = {
6206     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6207     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6208     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6209     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6210     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
6211     { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
6212     { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
6213     { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
6214     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
6215     { HCBT_SYSCOMMAND, hook },
6216     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
6217     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6218     { 0x00AE, sent|defwinproc|optional }, /* XP */
6219     { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
6220     { WM_INITMENU, sent|defwinproc },
6221     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6222     { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
6223     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6224     { WM_CAPTURECHANGED, sent|defwinproc },
6225     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
6226     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6227     { WM_EXITMENULOOP, sent|defwinproc },
6228     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
6229     { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
6230     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6231     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
6232     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6233     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6234     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6235     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6236     { 0 }
6237 };
6238 static const struct message WmAltVkN_2[] = {
6239     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6240     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6241     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6242     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6243     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
6244     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
6245     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6246     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
6247     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6248     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6249     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6250     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6251     { 0 }
6252 };
6253 static const struct message WmCtrlAltVkN[] = {
6254     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6255     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6256     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6257     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6258     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6259     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6260     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6261     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
6262     { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
6263     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6264     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
6265     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6266     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6267     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6268     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6269     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6270     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6271     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6272     { 0 }
6273 };
6274 static const struct message WmCtrlShiftVkN[] = {
6275     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6276     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6277     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6278     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
6279     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
6280     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
6281     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6282     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6283     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
6284     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6285     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6286     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6287     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
6288     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
6289     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
6290     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6291     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6292     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6293     { 0 }
6294 };
6295 static const struct message WmCtrlAltShiftVkN[] = {
6296     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6297     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6298     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6299     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6300     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6301     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6302     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
6303     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
6304     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
6305     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6306     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
6307     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
6308     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6309     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
6310     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6311     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
6312     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
6313     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
6314     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6315     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6316     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6317     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6318     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6319     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6320     { 0 }
6321 };
6322 static const struct message WmAltPressRelease[] = {
6323     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6324     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6325     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6326     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6327     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6328     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6329     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
6330     { HCBT_SYSCOMMAND, hook },
6331     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
6332     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6333     { WM_INITMENU, sent|defwinproc },
6334     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6335     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
6336     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
6337
6338     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
6339
6340     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6341     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
6342     { WM_CAPTURECHANGED, sent|defwinproc },
6343     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
6344     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6345     { WM_EXITMENULOOP, sent|defwinproc },
6346     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6347     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6348     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6349     { 0 }
6350 };
6351 static const struct message WmAltMouseButton[] = {
6352     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6353     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6354     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6355     { WM_MOUSEMOVE, wparam|optional, 0, 0 },
6356     { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
6357     { WM_LBUTTONDOWN, wparam, MK_LBUTTON, 0 },
6358     { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON, 0 },
6359     { WM_LBUTTONUP, wparam, 0, 0 },
6360     { WM_LBUTTONUP, sent|wparam, 0, 0 },
6361     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6362     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6363     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6364     { 0 }
6365 };
6366 static const struct message WmF1Seq[] = {
6367     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
6368     { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
6369     { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
6370     { WM_KEYF1, wparam|lparam, 0, 0 },
6371     { WM_KEYF1, sent|wparam|lparam, 0, 0 },
6372     { WM_HELP, sent|defwinproc },
6373     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
6374     { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
6375     { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
6376     { 0 }
6377 };
6378 static const struct message WmVkAppsSeq[] = {
6379     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
6380     { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
6381     { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
6382     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
6383     { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
6384     { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
6385     { WM_CONTEXTMENU, lparam, /*hwnd*/0, (LPARAM)-1 },
6386     { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, (LPARAM)-1 },
6387     { 0 }
6388 };
6389
6390 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
6391 {
6392     MSG msg;
6393
6394     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
6395     {
6396         struct message log_msg;
6397
6398         trace("accel: %p, %04x, %08lx, %08lx\n", msg.hwnd, msg.message, msg.wParam, msg.lParam);
6399
6400         /* ignore some unwanted messages */
6401         if (msg.message == WM_MOUSEMOVE ||
6402             msg.message == WM_GETICON ||
6403             msg.message == WM_TIMER ||
6404             msg.message == WM_DEVICECHANGE)
6405             continue;
6406
6407         log_msg.message = msg.message;
6408         log_msg.flags = wparam|lparam;
6409         log_msg.wParam = msg.wParam;
6410         log_msg.lParam = msg.lParam;
6411         add_message(&log_msg);
6412
6413         if (!hAccel || !TranslateAccelerator(hwnd, hAccel, &msg))
6414         {
6415             TranslateMessage(&msg);
6416             DispatchMessage(&msg);
6417         }
6418     }
6419 }
6420
6421 static void test_accelerators(void)
6422 {
6423     RECT rc;
6424     SHORT state;
6425     HACCEL hAccel;
6426     HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6427                                 100, 100, 200, 200, 0, 0, 0, NULL);
6428     BOOL ret;
6429
6430     assert(hwnd != 0);
6431     UpdateWindow(hwnd);
6432     flush_events();
6433     flush_sequence();
6434
6435     SetFocus(hwnd);
6436     ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
6437
6438     state = GetKeyState(VK_SHIFT);
6439     ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
6440     state = GetKeyState(VK_CAPITAL);
6441     ok(state == 0, "wrong CapsLock state %04x\n", state);
6442
6443     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(1));
6444     assert(hAccel != 0);
6445
6446     flush_events();
6447     pump_msg_loop(hwnd, 0);
6448     flush_sequence();
6449
6450     trace("testing VK_N press/release\n");
6451     flush_sequence();
6452     keybd_event('N', 0, 0, 0);
6453     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6454     pump_msg_loop(hwnd, hAccel);
6455     ok_sequence(WmVkN, "VK_N press/release", FALSE);
6456
6457     trace("testing Shift+VK_N press/release\n");
6458     flush_sequence();
6459     keybd_event(VK_SHIFT, 0, 0, 0);
6460     keybd_event('N', 0, 0, 0);
6461     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6462     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6463     pump_msg_loop(hwnd, hAccel);
6464     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
6465
6466     trace("testing Ctrl+VK_N press/release\n");
6467     flush_sequence();
6468     keybd_event(VK_CONTROL, 0, 0, 0);
6469     keybd_event('N', 0, 0, 0);
6470     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6471     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6472     pump_msg_loop(hwnd, hAccel);
6473     ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
6474
6475     trace("testing Alt+VK_N press/release\n");
6476     flush_sequence();
6477     keybd_event(VK_MENU, 0, 0, 0);
6478     keybd_event('N', 0, 0, 0);
6479     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6480     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6481     pump_msg_loop(hwnd, hAccel);
6482     ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
6483
6484     trace("testing Ctrl+Alt+VK_N press/release 1\n");
6485     flush_sequence();
6486     keybd_event(VK_CONTROL, 0, 0, 0);
6487     keybd_event(VK_MENU, 0, 0, 0);
6488     keybd_event('N', 0, 0, 0);
6489     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6490     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6491     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6492     pump_msg_loop(hwnd, hAccel);
6493     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
6494
6495     ret = DestroyAcceleratorTable(hAccel);
6496     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
6497
6498     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(2));
6499     assert(hAccel != 0);
6500
6501     trace("testing VK_N press/release\n");
6502     flush_sequence();
6503     keybd_event('N', 0, 0, 0);
6504     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6505     pump_msg_loop(hwnd, hAccel);
6506     ok_sequence(WmVkN, "VK_N press/release", FALSE);
6507
6508     trace("testing Shift+VK_N press/release\n");
6509     flush_sequence();
6510     keybd_event(VK_SHIFT, 0, 0, 0);
6511     keybd_event('N', 0, 0, 0);
6512     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6513     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6514     pump_msg_loop(hwnd, hAccel);
6515     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
6516
6517     trace("testing Ctrl+VK_N press/release 2\n");
6518     flush_sequence();
6519     keybd_event(VK_CONTROL, 0, 0, 0);
6520     keybd_event('N', 0, 0, 0);
6521     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6522     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6523     pump_msg_loop(hwnd, hAccel);
6524     ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
6525
6526     trace("testing Alt+VK_N press/release 2\n");
6527     flush_sequence();
6528     keybd_event(VK_MENU, 0, 0, 0);
6529     keybd_event('N', 0, 0, 0);
6530     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6531     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6532     pump_msg_loop(hwnd, hAccel);
6533     ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
6534
6535     trace("testing Ctrl+Alt+VK_N press/release 2\n");
6536     flush_sequence();
6537     keybd_event(VK_CONTROL, 0, 0, 0);
6538     keybd_event(VK_MENU, 0, 0, 0);
6539     keybd_event('N', 0, 0, 0);
6540     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6541     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6542     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6543     pump_msg_loop(hwnd, hAccel);
6544     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
6545
6546     trace("testing Ctrl+Shift+VK_N press/release\n");
6547     flush_sequence();
6548     keybd_event(VK_CONTROL, 0, 0, 0);
6549     keybd_event(VK_SHIFT, 0, 0, 0);
6550     keybd_event('N', 0, 0, 0);
6551     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6552     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6553     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6554     pump_msg_loop(hwnd, hAccel);
6555     ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
6556
6557     trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
6558     flush_sequence();
6559     keybd_event(VK_CONTROL, 0, 0, 0);
6560     keybd_event(VK_MENU, 0, 0, 0);
6561     keybd_event(VK_SHIFT, 0, 0, 0);
6562     keybd_event('N', 0, 0, 0);
6563     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6564     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6565     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6566     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6567     pump_msg_loop(hwnd, hAccel);
6568     ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
6569
6570     ret = DestroyAcceleratorTable(hAccel);
6571     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
6572
6573     trace("testing Alt press/release\n");
6574     flush_sequence();
6575     keybd_event(VK_MENU, 0, 0, 0);
6576     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6577     keybd_event(VK_MENU, 0, 0, 0);
6578     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6579     pump_msg_loop(hwnd, 0);
6580     /* this test doesn't pass in Wine for managed windows */
6581     ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
6582
6583     trace("testing Alt+MouseButton press/release\n");
6584     /* first, move mouse pointer inside of the window client area */
6585     GetClientRect(hwnd, &rc);
6586     MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
6587     rc.left += (rc.right - rc.left)/2;
6588     rc.top += (rc.bottom - rc.top)/2;
6589     SetCursorPos(rc.left, rc.top);
6590
6591     flush_events();
6592     flush_sequence();
6593     keybd_event(VK_MENU, 0, 0, 0);
6594     mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
6595     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
6596     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6597     pump_msg_loop(hwnd, 0);
6598     ok_sequence(WmAltMouseButton, "Alt+MouseButton press/release", FALSE);
6599
6600     trace("testing VK_F1 press/release\n");
6601     keybd_event(VK_F1, 0, 0, 0);
6602     keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
6603     pump_msg_loop(hwnd, 0);
6604     ok_sequence(WmF1Seq, "F1 press/release", FALSE);
6605
6606     trace("testing VK_APPS press/release\n");
6607     keybd_event(VK_APPS, 0, 0, 0);
6608     keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
6609     pump_msg_loop(hwnd, 0);
6610     ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
6611
6612     DestroyWindow(hwnd);
6613 }
6614
6615 /************* window procedures ********************/
6616
6617 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message, 
6618                              WPARAM wParam, LPARAM lParam)
6619 {
6620     static long defwndproc_counter = 0;
6621     static long beginpaint_counter = 0;
6622     LRESULT ret;
6623     struct message msg;
6624
6625     trace("%p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
6626
6627     /* explicitly ignore WM_GETICON message */
6628     if (message == WM_GETICON) return 0;
6629
6630     /* ignore registered messages */
6631     if (message >= 0xc000) return 0;
6632
6633     switch (message)
6634     {
6635         case WM_ENABLE:
6636         {
6637             LONG style = GetWindowLongA(hwnd, GWL_STYLE);
6638             ok((BOOL)wParam == !(style & WS_DISABLED),
6639                 "wrong WS_DISABLED state: %ld != %d\n", wParam, !(style & WS_DISABLED));
6640             break;
6641         }
6642
6643         case WM_CAPTURECHANGED:
6644             if (test_DestroyWindow_flag)
6645             {
6646                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
6647                 if (style & WS_CHILD)
6648                     lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
6649                 else if (style & WS_POPUP)
6650                     lParam = WND_POPUP_ID;
6651                 else
6652                     lParam = WND_PARENT_ID;
6653             }
6654             break;
6655
6656         case WM_NCDESTROY:
6657         {
6658             HWND capture;
6659
6660             ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
6661             capture = GetCapture();
6662             if (capture)
6663             {
6664                 ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
6665                 trace("current capture %p, releasing...\n", capture);
6666                 ReleaseCapture();
6667             }
6668         }
6669         /* fall through */
6670         case WM_DESTROY:
6671             if (pGetAncestor)
6672                 ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
6673             if (test_DestroyWindow_flag)
6674             {
6675                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
6676                 if (style & WS_CHILD)
6677                     lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
6678                 else if (style & WS_POPUP)
6679                     lParam = WND_POPUP_ID;
6680                 else
6681                     lParam = WND_PARENT_ID;
6682             }
6683             break;
6684
6685         /* test_accelerators() depends on this */
6686         case WM_NCHITTEST:
6687             return HTCLIENT;
6688     
6689         /* ignore */
6690         case WM_MOUSEMOVE:
6691         case WM_SETCURSOR:
6692         case WM_DEVICECHANGE:
6693             return 0;
6694
6695         case WM_WINDOWPOSCHANGING:
6696         case WM_WINDOWPOSCHANGED:
6697         {
6698             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
6699
6700             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
6701             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
6702                   winpos->hwnd, winpos->hwndInsertAfter,
6703                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
6704             dump_winpos_flags(winpos->flags);
6705
6706             /* Log only documented flags, win2k uses 0x1000 and 0x2000
6707              * in the high word for internal purposes
6708              */
6709             wParam = winpos->flags & 0xffff;
6710             /* We are not interested in the flags that don't match under XP and Win9x */
6711             wParam &= ~(SWP_NOZORDER);
6712             break;
6713         }
6714     }
6715
6716     msg.message = message;
6717     msg.flags = sent|wparam|lparam;
6718     if (defwndproc_counter) msg.flags |= defwinproc;
6719     if (beginpaint_counter) msg.flags |= beginpaint;
6720     msg.wParam = wParam;
6721     msg.lParam = lParam;
6722     add_message(&msg);
6723
6724     if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
6725     {
6726         HWND parent = GetParent(hwnd);
6727         RECT rc;
6728         MINMAXINFO *minmax = (MINMAXINFO *)lParam;
6729
6730         GetClientRect(parent, &rc);
6731         trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
6732         trace("Reserved=%d,%d MaxSize=%d,%d MaxPos=%d,%d MinTrack=%d,%d MaxTrack=%d,%d\n",
6733               minmax->ptReserved.x, minmax->ptReserved.y,
6734               minmax->ptMaxSize.x, minmax->ptMaxSize.y,
6735               minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
6736               minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
6737               minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
6738
6739         ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n",
6740            minmax->ptMaxSize.x, rc.right);
6741         ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %d != %d\n",
6742            minmax->ptMaxSize.y, rc.bottom);
6743     }
6744
6745     if (message == WM_PAINT)
6746     {
6747         PAINTSTRUCT ps;
6748         beginpaint_counter++;
6749         BeginPaint( hwnd, &ps );
6750         beginpaint_counter--;
6751         EndPaint( hwnd, &ps );
6752         return 0;
6753     }
6754
6755     defwndproc_counter++;
6756     ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam) 
6757                   : DefWindowProcA(hwnd, message, wParam, lParam);
6758     defwndproc_counter--;
6759
6760     return ret;
6761 }
6762
6763 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6764 {
6765     return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
6766 }
6767
6768 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6769 {
6770     return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
6771 }
6772
6773 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6774 {
6775     static long defwndproc_counter = 0;
6776     LRESULT ret;
6777     struct message msg;
6778
6779     trace("popup: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
6780
6781     switch (message)
6782     {
6783     case WM_GETICON:
6784         /* explicitly ignore WM_GETICON message */
6785         return 0;
6786     case WM_QUERYENDSESSION:
6787     case WM_ENDSESSION:
6788         lParam &= ~0x01;  /* Vista adds a 0x01 flag */
6789         break;
6790     }
6791
6792     msg.message = message;
6793     msg.flags = sent|wparam|lparam;
6794     if (defwndproc_counter) msg.flags |= defwinproc;
6795     msg.wParam = wParam;
6796     msg.lParam = lParam;
6797     add_message(&msg);
6798
6799     if (message == WM_CREATE)
6800     {
6801         DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
6802         SetWindowLongA(hwnd, GWL_STYLE, style);
6803     }
6804
6805     defwndproc_counter++;
6806     ret = DefWindowProcA(hwnd, message, wParam, lParam);
6807     defwndproc_counter--;
6808
6809     return ret;
6810 }
6811
6812 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6813 {
6814     static long defwndproc_counter = 0;
6815     static long beginpaint_counter = 0;
6816     LRESULT ret;
6817     struct message msg;
6818     LPARAM logged_lParam;
6819
6820     trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
6821
6822     /* explicitly ignore WM_GETICON message */
6823     if (message == WM_GETICON) return 0;
6824
6825     /* ignore registered messages */
6826     if (message >= 0xc000) return 0;
6827
6828     logged_lParam=lParam;
6829     if (log_all_parent_messages ||
6830         message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
6831         message == WM_SETFOCUS || message == WM_KILLFOCUS ||
6832         message == WM_ENABLE || message == WM_ENTERIDLE ||
6833         message == WM_DRAWITEM ||
6834         message == WM_IME_SETCONTEXT)
6835     {
6836         switch (message)
6837         {
6838             /* ignore */
6839             case WM_NCHITTEST:
6840                 return HTCLIENT;
6841             case WM_SETCURSOR:
6842             case WM_MOUSEMOVE:
6843                 return 0;
6844
6845             case WM_ERASEBKGND:
6846             {
6847                 RECT rc;
6848                 INT ret = GetClipBox((HDC)wParam, &rc);
6849
6850                 trace("WM_ERASEBKGND: GetClipBox()=%d, (%d,%d-%d,%d)\n",
6851                        ret, rc.left, rc.top, rc.right, rc.bottom);
6852                 break;
6853             }
6854
6855             case WM_WINDOWPOSCHANGING:
6856             case WM_WINDOWPOSCHANGED:
6857             {
6858                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
6859
6860                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
6861                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
6862                       winpos->hwnd, winpos->hwndInsertAfter,
6863                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
6864                 dump_winpos_flags(winpos->flags);
6865
6866                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
6867                  * in the high word for internal purposes
6868                  */
6869                 wParam = winpos->flags & 0xffff;
6870                 /* We are not interested in the flags that don't match under XP and Win9x */
6871                 wParam &= ~(SWP_NOZORDER);
6872                 break;
6873             }
6874
6875             case WM_DRAWITEM:
6876             {
6877                 /* encode DRAWITEMSTRUCT into an LPARAM */
6878                 DRAW_ITEM_STRUCT di;
6879                 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lParam;
6880
6881                 trace("WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x\n",
6882                       dis->CtlType, dis->CtlID, dis->itemID, dis->itemAction, dis->itemState);
6883
6884                 di.u.item.type = dis->CtlType;
6885                 di.u.item.ctl_id = dis->CtlID;
6886                 di.u.item.item_id = dis->itemID;
6887                 di.u.item.action = dis->itemAction;
6888                 di.u.item.state = dis->itemState;
6889
6890                 logged_lParam = di.u.lp;
6891                 break;
6892             }
6893         }
6894
6895         msg.message = message;
6896         msg.flags = sent|parent|wparam|lparam;
6897         if (defwndproc_counter) msg.flags |= defwinproc;
6898         if (beginpaint_counter) msg.flags |= beginpaint;
6899         msg.wParam = wParam;
6900         msg.lParam = logged_lParam;
6901         add_message(&msg);
6902     }
6903
6904     if (message == WM_PAINT)
6905     {
6906         PAINTSTRUCT ps;
6907         beginpaint_counter++;
6908         BeginPaint( hwnd, &ps );
6909         beginpaint_counter--;
6910         EndPaint( hwnd, &ps );
6911         return 0;
6912     }
6913
6914     defwndproc_counter++;
6915     ret = DefWindowProcA(hwnd, message, wParam, lParam);
6916     defwndproc_counter--;
6917
6918     return ret;
6919 }
6920
6921 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6922 {
6923     static long defwndproc_counter = 0;
6924     LRESULT ret;
6925     struct message msg;
6926
6927     trace("dialog: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
6928
6929     /* explicitly ignore WM_GETICON message */
6930     if (message == WM_GETICON) return 0;
6931
6932     /* ignore registered messages */
6933     if (message >= 0xc000) return 0;
6934
6935     if (test_def_id)
6936     {
6937         DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
6938         ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
6939         if (after_end_dialog)
6940             ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
6941         else
6942             ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
6943     }
6944
6945     switch (message)
6946     {
6947         case WM_WINDOWPOSCHANGING:
6948         case WM_WINDOWPOSCHANGED:
6949         {
6950             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
6951
6952             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
6953             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
6954                   winpos->hwnd, winpos->hwndInsertAfter,
6955                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
6956             dump_winpos_flags(winpos->flags);
6957
6958             /* Log only documented flags, win2k uses 0x1000 and 0x2000
6959              * in the high word for internal purposes
6960              */
6961             wParam = winpos->flags & 0xffff;
6962             /* We are not interested in the flags that don't match under XP and Win9x */
6963             wParam &= ~(SWP_NOZORDER);
6964             break;
6965         }
6966     }
6967
6968     msg.message = message;
6969     msg.flags = sent|wparam|lparam;
6970     if (defwndproc_counter) msg.flags |= defwinproc;
6971     msg.wParam = wParam;
6972     msg.lParam = lParam;
6973     add_message(&msg);
6974
6975     defwndproc_counter++;
6976     ret = DefDlgProcA(hwnd, message, wParam, lParam);
6977     defwndproc_counter--;
6978
6979     return ret;
6980 }
6981
6982 static void dump_winpos_flags(UINT flags)
6983 {
6984     if (!winetest_debug) return;
6985
6986     if (flags & SWP_SHOWWINDOW) printf("|SWP_SHOWWINDOW");
6987     if (flags & SWP_HIDEWINDOW) printf("|SWP_HIDEWINDOW");
6988     if (flags & SWP_NOACTIVATE) printf("|SWP_NOACTIVATE");
6989     if (flags & SWP_FRAMECHANGED) printf("|SWP_FRAMECHANGED");
6990     if (flags & SWP_NOCOPYBITS) printf("|SWP_NOCOPYBITS");
6991     if (flags & SWP_NOOWNERZORDER) printf("|SWP_NOOWNERZORDER");
6992     if (flags & SWP_NOSENDCHANGING) printf("|SWP_NOSENDCHANGING");
6993     if (flags & SWP_DEFERERASE) printf("|SWP_DEFERERASE");
6994     if (flags & SWP_ASYNCWINDOWPOS) printf("|SWP_ASYNCWINDOWPOS");
6995     if (flags & SWP_NOZORDER) printf("|SWP_NOZORDER");
6996     if (flags & SWP_NOREDRAW) printf("|SWP_NOREDRAW");
6997     if (flags & SWP_NOSIZE) printf("|SWP_NOSIZE");
6998     if (flags & SWP_NOMOVE) printf("|SWP_NOMOVE");
6999     if (flags & SWP_NOCLIENTSIZE) printf("|SWP_NOCLIENTSIZE");
7000     if (flags & SWP_NOCLIENTMOVE) printf("|SWP_NOCLIENTMOVE");
7001
7002 #define DUMPED_FLAGS \
7003     (SWP_NOSIZE | \
7004     SWP_NOMOVE | \
7005     SWP_NOZORDER | \
7006     SWP_NOREDRAW | \
7007     SWP_NOACTIVATE | \
7008     SWP_FRAMECHANGED | \
7009     SWP_SHOWWINDOW | \
7010     SWP_HIDEWINDOW | \
7011     SWP_NOCOPYBITS | \
7012     SWP_NOOWNERZORDER | \
7013     SWP_NOSENDCHANGING | \
7014     SWP_DEFERERASE | \
7015     SWP_ASYNCWINDOWPOS | \
7016     SWP_NOCLIENTSIZE | \
7017     SWP_NOCLIENTMOVE)
7018
7019     if(flags & ~DUMPED_FLAGS) printf("|0x%04x", flags & ~DUMPED_FLAGS);
7020     printf("\n");
7021 #undef DUMPED_FLAGS
7022 }
7023
7024 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7025 {
7026     static long defwndproc_counter = 0;
7027     LRESULT ret;
7028     struct message msg;
7029
7030     /* log only specific messages we are interested in */
7031     switch (message)
7032     {
7033 #if 0 /* probably log these as well */
7034     case WM_ACTIVATE:
7035     case WM_SETFOCUS:
7036     case WM_KILLFOCUS:
7037 #endif
7038     case WM_SHOWWINDOW:
7039         trace("WM_SHOWWINDOW %ld\n", wParam);
7040         break;
7041     case WM_SIZE:
7042         trace("WM_SIZE %ld\n", wParam);
7043         break;
7044     case WM_MOVE:
7045         trace("WM_MOVE\n");
7046         break;
7047     case WM_GETMINMAXINFO:
7048         trace("WM_GETMINMAXINFO\n");
7049         break;
7050
7051     case WM_WINDOWPOSCHANGING:
7052     case WM_WINDOWPOSCHANGED:
7053     {
7054         WINDOWPOS *winpos = (WINDOWPOS *)lParam;
7055
7056         trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
7057         trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
7058               winpos->hwnd, winpos->hwndInsertAfter,
7059               winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
7060         trace("flags: ");
7061         dump_winpos_flags(winpos->flags);
7062
7063         /* Log only documented flags, win2k uses 0x1000 and 0x2000
7064          * in the high word for internal purposes
7065          */
7066         wParam = winpos->flags & 0xffff;
7067         /* We are not interested in the flags that don't match under XP and Win9x */
7068         wParam &= ~(SWP_NOZORDER);
7069         break;
7070     }
7071
7072     default: /* ignore */
7073         /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
7074         return DefWindowProcA(hwnd, message, wParam, lParam);
7075     }
7076
7077     msg.message = message;
7078     msg.flags = sent|wparam|lparam;
7079     if (defwndproc_counter) msg.flags |= defwinproc;
7080     msg.wParam = wParam;
7081     msg.lParam = lParam;
7082     add_message(&msg);
7083
7084     defwndproc_counter++;
7085     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7086     defwndproc_counter--;
7087
7088     return ret;
7089 }
7090
7091 LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
7092 {
7093     switch (msg)
7094     {
7095         case WM_CREATE: return 0;
7096         case WM_PAINT:
7097         {
7098             MSG msg2;
7099             static int i = 0;
7100
7101             if (i < 256)
7102             {
7103                 i++;
7104                 if (PeekMessageA(&msg2, 0, 0, 0, 1))
7105                 {
7106                     TranslateMessage(&msg2);
7107                     DispatchMessage(&msg2);
7108                 }
7109                 i--;
7110             }
7111             else ok(broken(1), "infinite loop\n");
7112             if ( i == 0)
7113                 paint_loop_done = 1;
7114             return DefWindowProcA(hWnd,msg,wParam,lParam);
7115         }
7116     }
7117     return DefWindowProcA(hWnd,msg,wParam,lParam);
7118 }
7119
7120 static BOOL RegisterWindowClasses(void)
7121 {
7122     WNDCLASSA cls;
7123     WNDCLASSW clsW;
7124
7125     cls.style = 0;
7126     cls.lpfnWndProc = MsgCheckProcA;
7127     cls.cbClsExtra = 0;
7128     cls.cbWndExtra = 0;
7129     cls.hInstance = GetModuleHandleA(0);
7130     cls.hIcon = 0;
7131     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
7132     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
7133     cls.lpszMenuName = NULL;
7134     cls.lpszClassName = "TestWindowClass";
7135     if(!RegisterClassA(&cls)) return FALSE;
7136
7137     cls.lpfnWndProc = ShowWindowProcA;
7138     cls.lpszClassName = "ShowWindowClass";
7139     if(!RegisterClassA(&cls)) return FALSE;
7140
7141     cls.lpfnWndProc = PopupMsgCheckProcA;
7142     cls.lpszClassName = "TestPopupClass";
7143     if(!RegisterClassA(&cls)) return FALSE;
7144
7145     cls.lpfnWndProc = ParentMsgCheckProcA;
7146     cls.lpszClassName = "TestParentClass";
7147     if(!RegisterClassA(&cls)) return FALSE;
7148
7149     cls.lpfnWndProc = DefWindowProcA;
7150     cls.lpszClassName = "SimpleWindowClass";
7151     if(!RegisterClassA(&cls)) return FALSE;
7152
7153     cls.lpfnWndProc = PaintLoopProcA;
7154     cls.lpszClassName = "PaintLoopWindowClass";
7155     if(!RegisterClassA(&cls)) return FALSE;
7156
7157     cls.style = CS_NOCLOSE;
7158     cls.lpszClassName = "NoCloseWindowClass";
7159     if(!RegisterClassA(&cls)) return FALSE;
7160
7161     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
7162     cls.style = 0;
7163     cls.hInstance = GetModuleHandleA(0);
7164     cls.hbrBackground = 0;
7165     cls.lpfnWndProc = TestDlgProcA;
7166     cls.lpszClassName = "TestDialogClass";
7167     if(!RegisterClassA(&cls)) return FALSE;
7168
7169     clsW.style = 0;
7170     clsW.lpfnWndProc = MsgCheckProcW;
7171     clsW.cbClsExtra = 0;
7172     clsW.cbWndExtra = 0;
7173     clsW.hInstance = GetModuleHandleW(0);
7174     clsW.hIcon = 0;
7175     clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
7176     clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
7177     clsW.lpszMenuName = NULL;
7178     clsW.lpszClassName = testWindowClassW;
7179     RegisterClassW(&clsW);  /* ignore error, this fails on Win9x */
7180
7181     return TRUE;
7182 }
7183
7184 static BOOL is_our_logged_class(HWND hwnd)
7185 {
7186     char buf[256];
7187
7188     if (GetClassNameA(hwnd, buf, sizeof(buf)))
7189     {
7190         if (!lstrcmpiA(buf, "TestWindowClass") ||
7191             !lstrcmpiA(buf, "ShowWindowClass") ||
7192             !lstrcmpiA(buf, "TestParentClass") ||
7193             !lstrcmpiA(buf, "TestPopupClass") ||
7194             !lstrcmpiA(buf, "SimpleWindowClass") ||
7195             !lstrcmpiA(buf, "TestDialogClass") ||
7196             !lstrcmpiA(buf, "MDI_frame_class") ||
7197             !lstrcmpiA(buf, "MDI_client_class") ||
7198             !lstrcmpiA(buf, "MDI_child_class") ||
7199             !lstrcmpiA(buf, "my_button_class") ||
7200             !lstrcmpiA(buf, "my_edit_class") ||
7201             !lstrcmpiA(buf, "static") ||
7202             !lstrcmpiA(buf, "ListBox") ||
7203             !lstrcmpiA(buf, "ComboBox") ||
7204             !lstrcmpiA(buf, "MyDialogClass") ||
7205             !lstrcmpiA(buf, "#32770") ||
7206             !lstrcmpiA(buf, "#32768"))
7207         return TRUE;
7208         trace("ignoring window class %s\n", buf);
7209     }
7210     return FALSE;
7211 }
7212
7213 static HHOOK hCBT_hook;
7214 static DWORD cbt_hook_thread_id;
7215
7216 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
7217
7218     static const char * const CBT_code_name[10] = {
7219         "HCBT_MOVESIZE",
7220         "HCBT_MINMAX",
7221         "HCBT_QS",
7222         "HCBT_CREATEWND",
7223         "HCBT_DESTROYWND",
7224         "HCBT_ACTIVATE",
7225         "HCBT_CLICKSKIPPED",
7226         "HCBT_KEYSKIPPED",
7227         "HCBT_SYSCOMMAND",
7228         "HCBT_SETFOCUS" };
7229     const char *code_name = (nCode >= 0 && nCode <= HCBT_SETFOCUS) ? CBT_code_name[nCode] : "Unknown";
7230     HWND hwnd;
7231
7232     trace("CBT: %d (%s), %08lx, %08lx\n", nCode, code_name, wParam, lParam);
7233
7234     ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
7235
7236     if (nCode == HCBT_CLICKSKIPPED)
7237     {
7238         /* ignore this event, XP sends it a lot when switching focus between windows */
7239         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7240     }
7241
7242     if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
7243     {
7244         struct message msg;
7245
7246         msg.message = nCode;
7247         msg.flags = hook|wparam|lparam;
7248         msg.wParam = wParam;
7249         msg.lParam = lParam;
7250         add_message(&msg);
7251
7252         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7253     }
7254
7255     if (nCode == HCBT_DESTROYWND)
7256     {
7257         if (test_DestroyWindow_flag)
7258         {
7259             DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
7260             if (style & WS_CHILD)
7261                 lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
7262             else if (style & WS_POPUP)
7263                 lParam = WND_POPUP_ID;
7264             else
7265                 lParam = WND_PARENT_ID;
7266         }
7267     }
7268
7269     /* Log also SetFocus(0) calls */
7270     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
7271
7272     if (is_our_logged_class(hwnd))
7273     {
7274         struct message msg;
7275
7276         msg.message = nCode;
7277         msg.flags = hook|wparam|lparam;
7278         msg.wParam = wParam;
7279         msg.lParam = lParam;
7280         add_message(&msg);
7281     }
7282     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7283 }
7284
7285 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
7286                                     DWORD event,
7287                                     HWND hwnd,
7288                                     LONG object_id,
7289                                     LONG child_id,
7290                                     DWORD thread_id,
7291                                     DWORD event_time)
7292 {
7293     trace("WEH:%p,event %08x,hwnd %p,obj %08x,id %08x,thread %08x,time %08x\n",
7294            hevent, event, hwnd, object_id, child_id, thread_id, event_time);
7295
7296     ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
7297
7298     /* ignore mouse cursor events */
7299     if (object_id == OBJID_CURSOR) return;
7300
7301     if (!hwnd || is_our_logged_class(hwnd))
7302     {
7303         struct message msg;
7304
7305         msg.message = event;
7306         msg.flags = winevent_hook|wparam|lparam;
7307         msg.wParam = object_id;
7308         msg.lParam = child_id;
7309         add_message(&msg);
7310     }
7311 }
7312
7313 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
7314 static const WCHAR wszAnsi[] = {'U',0};
7315
7316 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
7317 {
7318     switch (uMsg)
7319     {
7320     case CB_FINDSTRINGEXACT:
7321         trace("String: %p\n", (LPCWSTR)lParam);
7322         if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
7323             return 1;
7324         if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
7325             return 0;
7326         return -1;
7327     }
7328     return DefWindowProcW(hwnd, uMsg, wParam, lParam);
7329 }
7330
7331 static const struct message WmGetTextLengthAfromW[] = {
7332     { WM_GETTEXTLENGTH, sent },
7333     { WM_GETTEXT, sent|optional },
7334     { 0 }
7335 };
7336
7337 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
7338
7339 /* dummy window proc for WM_GETTEXTLENGTH test */
7340 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
7341 {
7342     switch(msg)
7343     {
7344     case WM_GETTEXTLENGTH:
7345         return lstrlenW(dummy_window_text) + 37;  /* some random length */
7346     case WM_GETTEXT:
7347         lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
7348         return lstrlenW( (LPWSTR)lp );
7349     default:
7350         return DefWindowProcW( hwnd, msg, wp, lp );
7351     }
7352 }
7353
7354 static void test_message_conversion(void)
7355 {
7356     static const WCHAR wszMsgConversionClass[] =
7357         {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
7358     WNDCLASSW cls;
7359     LRESULT lRes;
7360     HWND hwnd;
7361     WNDPROC wndproc, newproc;
7362     BOOL ret;
7363
7364     cls.style = 0;
7365     cls.lpfnWndProc = MsgConversionProcW;
7366     cls.cbClsExtra = 0;
7367     cls.cbWndExtra = 0;
7368     cls.hInstance = GetModuleHandleW(NULL);
7369     cls.hIcon = NULL;
7370     cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
7371     cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
7372     cls.lpszMenuName = NULL;
7373     cls.lpszClassName = wszMsgConversionClass;
7374     /* this call will fail on Win9x, but that doesn't matter as this test is
7375      * meaningless on those platforms */
7376     if(!RegisterClassW(&cls)) return;
7377
7378     hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
7379                            100, 100, 200, 200, 0, 0, 0, NULL);
7380     ok(hwnd != NULL, "Window creation failed\n");
7381
7382     /* {W, A} -> A */
7383
7384     wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
7385     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7386     ok(lRes == 0, "String should have been converted\n");
7387     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7388     ok(lRes == 1, "String shouldn't have been converted\n");
7389
7390     /* {W, A} -> W */
7391
7392     wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
7393     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7394     ok(lRes == 1, "String shouldn't have been converted\n");
7395     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7396     ok(lRes == 1, "String shouldn't have been converted\n");
7397
7398     /* Synchronous messages */
7399
7400     lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7401     ok(lRes == 0, "String should have been converted\n");
7402     lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7403     ok(lRes == 1, "String shouldn't have been converted\n");
7404
7405     /* Asynchronous messages */
7406
7407     SetLastError(0);
7408     lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7409     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7410         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7411     SetLastError(0);
7412     lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7413     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7414         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7415     SetLastError(0);
7416     lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7417     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7418         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7419     SetLastError(0);
7420     lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7421     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7422         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7423     SetLastError(0);
7424     lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7425     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7426         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7427     SetLastError(0);
7428     lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7429     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7430         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7431     SetLastError(0);
7432     lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
7433     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7434         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7435     SetLastError(0);
7436     lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
7437     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7438         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7439
7440     /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
7441
7442     hwnd = CreateWindowW (testWindowClassW, wszUnicode,
7443                           WS_OVERLAPPEDWINDOW,
7444                           100, 100, 200, 200, 0, 0, 0, NULL);
7445     assert(hwnd);
7446     flush_sequence();
7447     lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
7448     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
7449     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
7450         "got bad length %ld\n", lRes );
7451
7452     flush_sequence();
7453     lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
7454                             hwnd, WM_GETTEXTLENGTH, 0, 0);
7455     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
7456     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
7457         "got bad length %ld\n", lRes );
7458
7459     wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
7460     newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
7461     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
7462     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
7463                                      NULL, 0, NULL, NULL ) ||
7464         broken(lRes == lstrlenW(dummy_window_text) + 37),
7465         "got bad length %ld\n", lRes );
7466
7467     SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc );  /* restore old wnd proc */
7468     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
7469     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
7470                                      NULL, 0, NULL, NULL ) ||
7471         broken(lRes == lstrlenW(dummy_window_text) + 37),
7472         "got bad length %ld\n", lRes );
7473
7474     ret = DestroyWindow(hwnd);
7475     ok( ret, "DestroyWindow() error %d\n", GetLastError());
7476 }
7477
7478 struct timer_info
7479 {
7480     HWND hWnd;
7481     HANDLE handles[2];
7482     DWORD id;
7483 };
7484
7485 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
7486 {
7487 }
7488
7489 #define TIMER_ID  0x19
7490
7491 static DWORD WINAPI timer_thread_proc(LPVOID x)
7492 {
7493     struct timer_info *info = x;
7494     DWORD r;
7495
7496     r = KillTimer(info->hWnd, 0x19);
7497     ok(r,"KillTimer failed in thread\n");
7498     r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
7499     ok(r,"SetTimer failed in thread\n");
7500     ok(r==TIMER_ID,"SetTimer id different\n");
7501     r = SetEvent(info->handles[0]);
7502     ok(r,"SetEvent failed in thread\n");
7503     return 0;
7504 }
7505
7506 static void test_timers(void)
7507 {
7508     struct timer_info info;
7509     DWORD id;
7510
7511     info.hWnd = CreateWindow ("TestWindowClass", NULL,
7512        WS_OVERLAPPEDWINDOW ,
7513        CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
7514        NULL, NULL, 0);
7515
7516     info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
7517     ok(info.id, "SetTimer failed\n");
7518     ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
7519     info.handles[0] = CreateEvent(NULL,0,0,NULL);
7520     info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
7521
7522     WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
7523
7524     WaitForSingleObject(info.handles[1], INFINITE);
7525
7526     CloseHandle(info.handles[0]);
7527     CloseHandle(info.handles[1]);
7528
7529     ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
7530
7531     ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
7532 }
7533
7534 static int count = 0;
7535 static VOID CALLBACK callback_count(
7536     HWND hwnd,
7537     UINT uMsg,
7538     UINT_PTR idEvent,
7539     DWORD dwTime
7540 )
7541 {
7542     count++;
7543 }
7544
7545 static void test_timers_no_wnd(void)
7546 {
7547     UINT_PTR id, id2;
7548     MSG msg;
7549
7550     count = 0;
7551     id = SetTimer(NULL, 0, 100, callback_count);
7552     ok(id != 0, "did not get id from SetTimer.\n");
7553     id2 = SetTimer(NULL, id, 200, callback_count);
7554     ok(id2 == id, "did not get same id from SetTimer when replacing (%li expected %li).\n", id2, id);
7555     Sleep(150);
7556     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7557     ok(count == 0, "did not get zero count as expected (%i).\n", count);
7558     Sleep(150);
7559     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7560     ok(count == 1, "did not get one count as expected (%i).\n", count);
7561     KillTimer(NULL, id);
7562     Sleep(250);
7563     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7564     ok(count == 1, "killing replaced timer did not work (%i).\n", count);
7565 }
7566
7567 /* Various win events with arbitrary parameters */
7568 static const struct message WmWinEventsSeq[] = {
7569     { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
7570     { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7571     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
7572     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
7573     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
7574     { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
7575     { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
7576     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
7577     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
7578     /* our win event hook ignores OBJID_CURSOR events */
7579     /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
7580     { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
7581     { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
7582     { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
7583     { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
7584     { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
7585     { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7586     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
7587     { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
7588     { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
7589     { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
7590     { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
7591     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
7592     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
7593     { 0 }
7594 };
7595 static const struct message WmWinEventCaretSeq[] = {
7596     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7597     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7598     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
7599     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7600     { 0 }
7601 };
7602 static const struct message WmWinEventCaretSeq_2[] = {
7603     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7604     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7605     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7606     { 0 }
7607 };
7608 static const struct message WmWinEventAlertSeq[] = {
7609     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
7610     { 0 }
7611 };
7612 static const struct message WmWinEventAlertSeq_2[] = {
7613     /* create window in the thread proc */
7614     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
7615     /* our test event */
7616     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
7617     { 0 }
7618 };
7619 static const struct message WmGlobalHookSeq_1[] = {
7620     /* create window in the thread proc */
7621     { HCBT_CREATEWND, hook|lparam, 0, 2 },
7622     /* our test events */
7623     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
7624     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
7625     { 0 }
7626 };
7627 static const struct message WmGlobalHookSeq_2[] = {
7628     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
7629     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
7630     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
7631     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
7632     { 0 }
7633 };
7634
7635 static const struct message WmMouseLLHookSeq[] = {
7636     { WM_MOUSEMOVE, hook },
7637     { WM_LBUTTONUP, hook },
7638     { WM_MOUSEMOVE, hook },
7639     { 0 }
7640 };
7641
7642 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
7643                                          DWORD event,
7644                                          HWND hwnd,
7645                                          LONG object_id,
7646                                          LONG child_id,
7647                                          DWORD thread_id,
7648                                          DWORD event_time)
7649 {
7650     char buf[256];
7651
7652     trace("WEH_2:%p,event %08x,hwnd %p,obj %08x,id %08x,thread %08x,time %08x\n",
7653            hevent, event, hwnd, object_id, child_id, thread_id, event_time);
7654
7655     if (GetClassNameA(hwnd, buf, sizeof(buf)))
7656     {
7657         if (!lstrcmpiA(buf, "TestWindowClass") ||
7658             !lstrcmpiA(buf, "static"))
7659         {
7660             struct message msg;
7661
7662             msg.message = event;
7663             msg.flags = winevent_hook|wparam|lparam;
7664             msg.wParam = object_id;
7665             msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
7666             add_message(&msg);
7667         }
7668     }
7669 }
7670
7671 static HHOOK hCBT_global_hook;
7672 static DWORD cbt_global_hook_thread_id;
7673
7674 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
7675
7676     HWND hwnd;
7677     char buf[256];
7678
7679     trace("CBT_2: %d, %08lx, %08lx\n", nCode, wParam, lParam);
7680
7681     if (nCode == HCBT_SYSCOMMAND)
7682     {
7683         struct message msg;
7684
7685         msg.message = nCode;
7686         msg.flags = hook|wparam|lparam;
7687         msg.wParam = wParam;
7688         msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
7689         add_message(&msg);
7690
7691         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
7692     }
7693     /* WH_MOUSE_LL hook */
7694     if (nCode == HC_ACTION)
7695     {
7696         MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
7697
7698         /* we can't test for real mouse events */
7699         if (mhll->flags & LLMHF_INJECTED)
7700         {
7701             struct message msg;
7702
7703             memset (&msg, 0, sizeof (msg));
7704             msg.message = wParam;
7705             msg.flags = hook;
7706             add_message(&msg);
7707         }
7708         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
7709     }
7710
7711     /* Log also SetFocus(0) calls */
7712     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
7713
7714     if (GetClassNameA(hwnd, buf, sizeof(buf)))
7715     {
7716         if (!lstrcmpiA(buf, "TestWindowClass") ||
7717             !lstrcmpiA(buf, "static"))
7718         {
7719             struct message msg;
7720
7721             msg.message = nCode;
7722             msg.flags = hook|wparam|lparam;
7723             msg.wParam = wParam;
7724             msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
7725             add_message(&msg);
7726         }
7727     }
7728     return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
7729 }
7730
7731 static DWORD WINAPI win_event_global_thread_proc(void *param)
7732 {
7733     HWND hwnd;
7734     MSG msg;
7735     HANDLE hevent = *(HANDLE *)param;
7736
7737     assert(pNotifyWinEvent);
7738
7739     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
7740     assert(hwnd);
7741     trace("created thread window %p\n", hwnd);
7742
7743     *(HWND *)param = hwnd;
7744
7745     flush_sequence();
7746     /* this event should be received only by our new hook proc,
7747      * an old one does not expect an event from another thread.
7748      */
7749     pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
7750     SetEvent(hevent);
7751
7752     while (GetMessage(&msg, 0, 0, 0))
7753     {
7754         TranslateMessage(&msg);
7755         DispatchMessage(&msg);
7756     }
7757     return 0;
7758 }
7759
7760 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
7761 {
7762     HWND hwnd;
7763     MSG msg;
7764     HANDLE hevent = *(HANDLE *)param;
7765
7766     flush_sequence();
7767     /* these events should be received only by our new hook proc,
7768      * an old one does not expect an event from another thread.
7769      */
7770
7771     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
7772     assert(hwnd);
7773     trace("created thread window %p\n", hwnd);
7774
7775     *(HWND *)param = hwnd;
7776
7777     /* Windows doesn't like when a thread plays games with the focus,
7778        that leads to all kinds of misbehaviours and failures to activate
7779        a window. So, better keep next lines commented out.
7780     SetFocus(0);
7781     SetFocus(hwnd);*/
7782
7783     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
7784     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
7785
7786     SetEvent(hevent);
7787
7788     while (GetMessage(&msg, 0, 0, 0))
7789     {
7790         TranslateMessage(&msg);
7791         DispatchMessage(&msg);
7792     }
7793     return 0;
7794 }
7795
7796 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
7797 {
7798     HWND hwnd;
7799     MSG msg;
7800     HANDLE hevent = *(HANDLE *)param;
7801
7802     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
7803     assert(hwnd);
7804     trace("created thread window %p\n", hwnd);
7805
7806     *(HWND *)param = hwnd;
7807
7808     flush_sequence();
7809
7810     /* Windows doesn't like when a thread plays games with the focus,
7811      * that leads to all kinds of misbehaviours and failures to activate
7812      * a window. So, better don't generate a mouse click message below.
7813      */
7814     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
7815     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
7816     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
7817
7818     SetEvent(hevent);
7819     while (GetMessage(&msg, 0, 0, 0))
7820     {
7821         TranslateMessage(&msg);
7822         DispatchMessage(&msg);
7823     }
7824     return 0;
7825 }
7826
7827 static void test_winevents(void)
7828 {
7829     BOOL ret;
7830     MSG msg;
7831     HWND hwnd, hwnd2;
7832     UINT i;
7833     HANDLE hthread, hevent;
7834     DWORD tid;
7835     HWINEVENTHOOK hhook;
7836     const struct message *events = WmWinEventsSeq;
7837
7838     hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
7839                            WS_OVERLAPPEDWINDOW,
7840                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
7841                            NULL, NULL, 0);
7842     assert(hwnd);
7843
7844     /****** start of global hook test *************/
7845     hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
7846     if (!hCBT_global_hook)
7847     {
7848         ok(DestroyWindow(hwnd), "failed to destroy window\n");
7849         skip( "cannot set global hook\n" );
7850         return;
7851     }
7852
7853     hevent = CreateEventA(NULL, 0, 0, NULL);
7854     assert(hevent);
7855     hwnd2 = (HWND)hevent;
7856
7857     hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
7858     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7859
7860     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7861
7862     ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
7863
7864     flush_sequence();
7865     /* this one should be received only by old hook proc */
7866     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
7867     /* this one should be received only by old hook proc */
7868     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
7869
7870     ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
7871
7872     ret = UnhookWindowsHookEx(hCBT_global_hook);
7873     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
7874
7875     PostThreadMessageA(tid, WM_QUIT, 0, 0);
7876     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7877     CloseHandle(hthread);
7878     CloseHandle(hevent);
7879     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7880     /****** end of global hook test *************/
7881
7882     if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
7883     {
7884         ok(DestroyWindow(hwnd), "failed to destroy window\n");
7885         return;
7886     }
7887
7888     flush_sequence();
7889
7890     if (0)
7891     {
7892     /* this test doesn't pass under Win9x */
7893     /* win2k ignores events with hwnd == 0 */
7894     SetLastError(0xdeadbeef);
7895     pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
7896     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
7897        GetLastError() == 0xdeadbeef, /* Win9x */
7898        "unexpected error %d\n", GetLastError());
7899     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
7900     }
7901
7902     for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++)
7903         pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
7904
7905     ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
7906
7907     /****** start of event filtering test *************/
7908     hhook = (HWINEVENTHOOK)pSetWinEventHook(
7909         EVENT_OBJECT_SHOW, /* 0x8002 */
7910         EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
7911         GetModuleHandleA(0), win_event_global_hook_proc,
7912         GetCurrentProcessId(), 0,
7913         WINEVENT_INCONTEXT);
7914     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
7915
7916     hevent = CreateEventA(NULL, 0, 0, NULL);
7917     assert(hevent);
7918     hwnd2 = (HWND)hevent;
7919
7920     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
7921     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7922
7923     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7924
7925     ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
7926
7927     flush_sequence();
7928     /* this one should be received only by old hook proc */
7929     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
7930     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
7931     /* this one should be received only by old hook proc */
7932     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
7933
7934     ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
7935
7936     ret = pUnhookWinEvent(hhook);
7937     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
7938
7939     PostThreadMessageA(tid, WM_QUIT, 0, 0);
7940     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7941     CloseHandle(hthread);
7942     CloseHandle(hevent);
7943     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7944     /****** end of event filtering test *************/
7945
7946     /****** start of out of context event test *************/
7947     hhook = (HWINEVENTHOOK)pSetWinEventHook(
7948         EVENT_MIN, EVENT_MAX,
7949         0, win_event_global_hook_proc,
7950         GetCurrentProcessId(), 0,
7951         WINEVENT_OUTOFCONTEXT);
7952     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
7953
7954     hevent = CreateEventA(NULL, 0, 0, NULL);
7955     assert(hevent);
7956     hwnd2 = (HWND)hevent;
7957
7958     flush_sequence();
7959
7960     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
7961     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7962
7963     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7964
7965     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
7966     /* process pending winevent messages */
7967     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
7968     ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
7969
7970     flush_sequence();
7971     /* this one should be received only by old hook proc */
7972     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
7973     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
7974     /* this one should be received only by old hook proc */
7975     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
7976
7977     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
7978     /* process pending winevent messages */
7979     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
7980     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
7981
7982     ret = pUnhookWinEvent(hhook);
7983     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
7984
7985     PostThreadMessageA(tid, WM_QUIT, 0, 0);
7986     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7987     CloseHandle(hthread);
7988     CloseHandle(hevent);
7989     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7990     /****** end of out of context event test *************/
7991
7992     /****** start of MOUSE_LL hook test *************/
7993     hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
7994     /* WH_MOUSE_LL is not supported on Win9x platforms */
7995     if (!hCBT_global_hook)
7996     {
7997         trace("Skipping WH_MOUSE_LL test on this platform\n");
7998         goto skip_mouse_ll_hook_test;
7999     }
8000
8001     hevent = CreateEventA(NULL, 0, 0, NULL);
8002     assert(hevent);
8003     hwnd2 = (HWND)hevent;
8004
8005     hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
8006     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8007
8008     while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
8009         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
8010
8011     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
8012     flush_sequence();
8013
8014     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8015     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
8016     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8017
8018     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
8019
8020     ret = UnhookWindowsHookEx(hCBT_global_hook);
8021     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
8022
8023     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8024     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8025     CloseHandle(hthread);
8026     CloseHandle(hevent);
8027     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8028     /****** end of MOUSE_LL hook test *************/
8029 skip_mouse_ll_hook_test:
8030
8031     ok(DestroyWindow(hwnd), "failed to destroy window\n");
8032 }
8033
8034 static void test_set_hook(void)
8035 {
8036     BOOL ret;
8037     HHOOK hhook;
8038     HWINEVENTHOOK hwinevent_hook;
8039
8040     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
8041     ok(hhook != 0, "local hook does not require hModule set to 0\n");
8042     UnhookWindowsHookEx(hhook);
8043
8044     if (0)
8045     {
8046     /* this test doesn't pass under Win9x: BUG! */
8047     SetLastError(0xdeadbeef);
8048     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
8049     ok(!hhook, "global hook requires hModule != 0\n");
8050     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
8051     }
8052
8053     SetLastError(0xdeadbeef);
8054     hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
8055     ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
8056     ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
8057        GetLastError() == 0xdeadbeef, /* Win9x */
8058        "unexpected error %d\n", GetLastError());
8059
8060     SetLastError(0xdeadbeef);
8061     ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
8062     ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
8063        GetLastError() == 0xdeadbeef, /* Win9x */
8064        "unexpected error %d\n", GetLastError());
8065
8066     if (!pSetWinEventHook || !pUnhookWinEvent) return;
8067
8068     /* even process local incontext hooks require hmodule */
8069     SetLastError(0xdeadbeef);
8070     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
8071         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
8072     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
8073     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
8074        GetLastError() == 0xdeadbeef, /* Win9x */
8075        "unexpected error %d\n", GetLastError());
8076
8077     /* even thread local incontext hooks require hmodule */
8078     SetLastError(0xdeadbeef);
8079     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
8080         0, win_event_proc, GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
8081     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
8082     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
8083        GetLastError() == 0xdeadbeef, /* Win9x */
8084        "unexpected error %d\n", GetLastError());
8085
8086     if (0)
8087     {
8088     /* these 3 tests don't pass under Win9x */
8089     SetLastError(0xdeadbeef);
8090     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(1, 0,
8091         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8092     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
8093     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
8094
8095     SetLastError(0xdeadbeef);
8096     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(-1, 1,
8097         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8098     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
8099     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
8100
8101     SetLastError(0xdeadbeef);
8102     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
8103         0, win_event_proc, 0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
8104     ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
8105     ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
8106     }
8107
8108     SetLastError(0xdeadbeef);
8109     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(0, 0,
8110         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8111     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
8112     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
8113     ret = pUnhookWinEvent(hwinevent_hook);
8114     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8115
8116 todo_wine {
8117     /* This call succeeds under win2k SP4, but fails under Wine.
8118        Does win2k test/use passed process id? */
8119     SetLastError(0xdeadbeef);
8120     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
8121         0, win_event_proc, 0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
8122     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
8123     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
8124     ret = pUnhookWinEvent(hwinevent_hook);
8125     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8126 }
8127
8128     SetLastError(0xdeadbeef);
8129     ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
8130     ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
8131         GetLastError() == 0xdeadbeef, /* Win9x */
8132         "unexpected error %d\n", GetLastError());
8133 }
8134
8135 static const struct message ScrollWindowPaint1[] = {
8136     { WM_PAINT, sent },
8137     { WM_ERASEBKGND, sent|beginpaint },
8138     { 0 }
8139 };
8140
8141 static const struct message ScrollWindowPaint2[] = {
8142     { WM_PAINT, sent },
8143     { 0 }
8144 };
8145
8146 static void test_scrollwindowex(void)
8147 {
8148     HWND hwnd, hchild;
8149     RECT rect={0,0,130,130};
8150
8151     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
8152             WS_VISIBLE|WS_OVERLAPPEDWINDOW,
8153             100, 100, 200, 200, 0, 0, 0, NULL);
8154     ok (hwnd != 0, "Failed to create overlapped window\n");
8155     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", 
8156             WS_VISIBLE|WS_CAPTION|WS_CHILD,
8157             10, 10, 150, 150, hwnd, 0, 0, NULL);
8158     ok (hchild != 0, "Failed to create child\n");
8159     UpdateWindow(hwnd);
8160     flush_events();
8161     flush_sequence();
8162
8163     /* scroll without the child window */
8164     trace("start scroll\n");
8165     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
8166             SW_ERASE|SW_INVALIDATE);
8167     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
8168     trace("end scroll\n");
8169     flush_sequence();
8170     flush_events();
8171     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
8172     flush_events();
8173     flush_sequence();
8174
8175     /* Now without the SW_ERASE flag */
8176     trace("start scroll\n");
8177     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
8178     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
8179     trace("end scroll\n");
8180     flush_sequence();
8181     flush_events();
8182     ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", 0);
8183     flush_events();
8184     flush_sequence();
8185
8186     /* now scroll the child window as well */
8187     trace("start scroll\n");
8188     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
8189             SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
8190     todo_wine { /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
8191                 /* windows sometimes a WM_MOVE */
8192         ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
8193     }
8194     trace("end scroll\n");
8195     flush_sequence();
8196     flush_events();
8197     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
8198     flush_events();
8199     flush_sequence();
8200
8201     /* now scroll with ScrollWindow() */
8202     trace("start scroll with ScrollWindow\n");
8203     ScrollWindow( hwnd, 5, 5, NULL, NULL);
8204     trace("end scroll\n");
8205     flush_sequence();
8206     flush_events();
8207     ok_sequence(ScrollWindowPaint1, "ScrollWindow", 0);
8208
8209     ok(DestroyWindow(hchild), "failed to destroy window\n");
8210     ok(DestroyWindow(hwnd), "failed to destroy window\n");
8211     flush_sequence();
8212 }
8213
8214 static const struct message destroy_window_with_children[] = {
8215     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
8216     { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
8217     { 0x0090, sent|optional },
8218     { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
8219     { 0x0090, sent|optional },
8220     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
8221     { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8222     { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8223     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8224     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
8225     { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
8226     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
8227     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
8228     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
8229     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
8230     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
8231     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
8232     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
8233     { 0 }
8234 };
8235
8236 static void test_DestroyWindow(void)
8237 {
8238     BOOL ret;
8239     HWND parent, child1, child2, child3, child4, test;
8240     UINT child_id = WND_CHILD_ID + 1;
8241
8242     parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8243                              100, 100, 200, 200, 0, 0, 0, NULL);
8244     assert(parent != 0);
8245     child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8246                              0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
8247     assert(child1 != 0);
8248     child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8249                              0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
8250     assert(child2 != 0);
8251     child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8252                              0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
8253     assert(child3 != 0);
8254     child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
8255                              0, 0, 50, 50, parent, 0, 0, NULL);
8256     assert(child4 != 0);
8257
8258     /* test owner/parent of child2 */
8259     test = GetParent(child2);
8260     ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8261     ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
8262     if(pGetAncestor) {
8263         test = pGetAncestor(child2, GA_PARENT);
8264         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8265     }
8266     test = GetWindow(child2, GW_OWNER);
8267     ok(!test, "wrong owner %p\n", test);
8268
8269     test = SetParent(child2, parent);
8270     ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
8271
8272     /* test owner/parent of the parent */
8273     test = GetParent(parent);
8274     ok(!test, "wrong parent %p\n", test);
8275     ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
8276     if(pGetAncestor) {
8277         test = pGetAncestor(parent, GA_PARENT);
8278         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8279     }
8280     test = GetWindow(parent, GW_OWNER);
8281     ok(!test, "wrong owner %p\n", test);
8282
8283     /* test owner/parent of child1 */
8284     test = GetParent(child1);
8285     ok(test == parent, "wrong parent %p\n", test);
8286     ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
8287     if(pGetAncestor) {
8288         test = pGetAncestor(child1, GA_PARENT);
8289         ok(test == parent, "wrong parent %p\n", test);
8290     }
8291     test = GetWindow(child1, GW_OWNER);
8292     ok(!test, "wrong owner %p\n", test);
8293
8294     /* test owner/parent of child2 */
8295     test = GetParent(child2);
8296     ok(test == parent, "wrong parent %p\n", test);
8297     ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
8298     if(pGetAncestor) {
8299         test = pGetAncestor(child2, GA_PARENT);
8300         ok(test == parent, "wrong parent %p\n", test);
8301     }
8302     test = GetWindow(child2, GW_OWNER);
8303     ok(!test, "wrong owner %p\n", test);
8304
8305     /* test owner/parent of child3 */
8306     test = GetParent(child3);
8307     ok(test == child1, "wrong parent %p\n", test);
8308     ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
8309     if(pGetAncestor) {
8310         test = pGetAncestor(child3, GA_PARENT);
8311         ok(test == child1, "wrong parent %p\n", test);
8312     }
8313     test = GetWindow(child3, GW_OWNER);
8314     ok(!test, "wrong owner %p\n", test);
8315
8316     /* test owner/parent of child4 */
8317     test = GetParent(child4);
8318     ok(test == parent, "wrong parent %p\n", test);
8319     ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
8320     if(pGetAncestor) {
8321         test = pGetAncestor(child4, GA_PARENT);
8322         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8323     }
8324     test = GetWindow(child4, GW_OWNER);
8325     ok(test == parent, "wrong owner %p\n", test);
8326
8327     flush_sequence();
8328
8329     trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
8330            parent, child1, child2, child3, child4);
8331
8332     SetCapture(child4);
8333     test = GetCapture();
8334     ok(test == child4, "wrong capture window %p\n", test);
8335
8336     test_DestroyWindow_flag = TRUE;
8337     ret = DestroyWindow(parent);
8338     ok( ret, "DestroyWindow() error %d\n", GetLastError());
8339     test_DestroyWindow_flag = FALSE;
8340     ok_sequence(destroy_window_with_children, "destroy window with children", 0);
8341
8342     ok(!IsWindow(parent), "parent still exists\n");
8343     ok(!IsWindow(child1), "child1 still exists\n");
8344     ok(!IsWindow(child2), "child2 still exists\n");
8345     ok(!IsWindow(child3), "child3 still exists\n");
8346     ok(!IsWindow(child4), "child4 still exists\n");
8347
8348     test = GetCapture();
8349     ok(!test, "wrong capture window %p\n", test);
8350 }
8351
8352
8353 static const struct message WmDispatchPaint[] = {
8354     { WM_NCPAINT, sent },
8355     { WM_GETTEXT, sent|defwinproc|optional },
8356     { WM_GETTEXT, sent|defwinproc|optional },
8357     { WM_ERASEBKGND, sent },
8358     { 0 }
8359 };
8360
8361 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8362 {
8363     if (message == WM_PAINT) return 0;
8364     return MsgCheckProcA( hwnd, message, wParam, lParam );
8365 }
8366
8367 static void test_DispatchMessage(void)
8368 {
8369     RECT rect;
8370     MSG msg;
8371     int count;
8372     HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8373                                100, 100, 200, 200, 0, 0, 0, NULL);
8374     ShowWindow( hwnd, SW_SHOW );
8375     UpdateWindow( hwnd );
8376     flush_events();
8377     flush_sequence();
8378     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
8379
8380     SetRect( &rect, -5, -5, 5, 5 );
8381     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
8382     count = 0;
8383     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
8384     {
8385         if (msg.message != WM_PAINT) DispatchMessage( &msg );
8386         else
8387         {
8388             flush_sequence();
8389             DispatchMessage( &msg );
8390             /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
8391             if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
8392             else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
8393             if (++count > 10) break;
8394         }
8395     }
8396     ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
8397
8398     trace("now without DispatchMessage\n");
8399     flush_sequence();
8400     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
8401     count = 0;
8402     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
8403     {
8404         if (msg.message != WM_PAINT) DispatchMessage( &msg );
8405         else
8406         {
8407             HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
8408             flush_sequence();
8409             /* this will send WM_NCCPAINT just like DispatchMessage does */
8410             GetUpdateRgn( hwnd, hrgn, TRUE );
8411             ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
8412             DeleteObject( hrgn );
8413             GetClientRect( hwnd, &rect );
8414             ValidateRect( hwnd, &rect );  /* this will stop WM_PAINTs */
8415             ok( !count, "Got multiple WM_PAINTs\n" );
8416             if (++count > 10) break;
8417         }
8418     }
8419     DestroyWindow(hwnd);
8420 }
8421
8422
8423 static const struct message WmUser[] = {
8424     { WM_USER, sent },
8425     { 0 }
8426 };
8427
8428 struct sendmsg_info
8429 {
8430     HWND  hwnd;
8431     DWORD timeout;
8432     DWORD ret;
8433 };
8434
8435 static DWORD CALLBACK send_msg_thread( LPVOID arg )
8436 {
8437     struct sendmsg_info *info = arg;
8438     info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
8439     if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT, "unexpected error %d\n", GetLastError());
8440     return 0;
8441 }
8442
8443 static void wait_for_thread( HANDLE thread )
8444 {
8445     while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
8446     {
8447         MSG msg;
8448         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage(&msg);
8449     }
8450 }
8451
8452 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8453 {
8454     if (message == WM_USER) Sleep(200);
8455     return MsgCheckProcA( hwnd, message, wParam, lParam );
8456 }
8457
8458 static void test_SendMessageTimeout(void)
8459 {
8460     HANDLE thread;
8461     struct sendmsg_info info;
8462     DWORD tid;
8463
8464     info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8465                                100, 100, 200, 200, 0, 0, 0, NULL);
8466     flush_events();
8467     flush_sequence();
8468
8469     info.timeout = 1000;
8470     info.ret = 0xdeadbeef;
8471     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8472     wait_for_thread( thread );
8473     CloseHandle( thread );
8474     ok( info.ret == 1, "SendMessageTimeout failed\n" );
8475     ok_sequence( WmUser, "WmUser", FALSE );
8476
8477     info.timeout = 1;
8478     info.ret = 0xdeadbeef;
8479     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8480     Sleep(100);  /* SendMessageTimeout should time out here */
8481     wait_for_thread( thread );
8482     CloseHandle( thread );
8483     ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
8484     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8485
8486     /* 0 means infinite timeout */
8487     info.timeout = 0;
8488     info.ret = 0xdeadbeef;
8489     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8490     Sleep(100);
8491     wait_for_thread( thread );
8492     CloseHandle( thread );
8493     ok( info.ret == 1, "SendMessageTimeout failed\n" );
8494     ok_sequence( WmUser, "WmUser", FALSE );
8495
8496     /* timeout is treated as signed despite the prototype */
8497     info.timeout = 0x7fffffff;
8498     info.ret = 0xdeadbeef;
8499     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8500     Sleep(100);
8501     wait_for_thread( thread );
8502     CloseHandle( thread );
8503     ok( info.ret == 1, "SendMessageTimeout failed\n" );
8504     ok_sequence( WmUser, "WmUser", FALSE );
8505
8506     info.timeout = 0x80000000;
8507     info.ret = 0xdeadbeef;
8508     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8509     Sleep(100);
8510     wait_for_thread( thread );
8511     CloseHandle( thread );
8512     ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
8513     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8514
8515     /* now check for timeout during message processing */
8516     SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
8517     info.timeout = 100;
8518     info.ret = 0xdeadbeef;
8519     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8520     wait_for_thread( thread );
8521     CloseHandle( thread );
8522     /* we should time out but still get the message */
8523     ok( info.ret == 0, "SendMessageTimeout failed\n" );
8524     ok_sequence( WmUser, "WmUser", FALSE );
8525
8526     DestroyWindow( info.hwnd );
8527 }
8528
8529
8530 /****************** edit message test *************************/
8531 #define ID_EDIT 0x1234
8532 static const struct message sl_edit_setfocus[] =
8533 {
8534     { HCBT_SETFOCUS, hook },
8535     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
8536     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8537     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8538     { WM_SETFOCUS, sent|wparam, 0 },
8539     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8540     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 },
8541     { WM_CTLCOLOREDIT, sent|parent },
8542     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8543     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8544     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8545     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8546     { 0 }
8547 };
8548 static const struct message ml_edit_setfocus[] =
8549 {
8550     { HCBT_SETFOCUS, hook },
8551     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
8552     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8553     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8554     { WM_SETFOCUS, sent|wparam, 0 },
8555     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8556     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8557     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8558     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8559     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8560     { 0 }
8561 };
8562 static const struct message sl_edit_killfocus[] =
8563 {
8564     { HCBT_SETFOCUS, hook },
8565     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8566     { WM_KILLFOCUS, sent|wparam, 0 },
8567     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8568     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8569     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
8570     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
8571     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
8572     { 0 }
8573 };
8574 static const struct message sl_edit_lbutton_dblclk[] =
8575 {
8576     { WM_LBUTTONDBLCLK, sent },
8577     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8578     { 0 }
8579 };
8580 static const struct message sl_edit_lbutton_down[] =
8581 {
8582     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
8583     { HCBT_SETFOCUS, hook },
8584     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
8585     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8586     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8587     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
8588     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8589     { WM_CTLCOLOREDIT, sent|parent },
8590     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8591     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8592     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8593     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8594     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8595     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8596     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8597     { WM_CTLCOLOREDIT, sent|parent|optional },
8598     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8599     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8600     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8601     { 0 }
8602 };
8603 static const struct message ml_edit_lbutton_down[] =
8604 {
8605     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
8606     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8607     { HCBT_SETFOCUS, hook },
8608     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
8609     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8610     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8611     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
8612     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8613     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8614     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8615     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8616     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8617     { 0 }
8618 };
8619 static const struct message sl_edit_lbutton_up[] =
8620 {
8621     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
8622     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8623     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8624     { WM_CAPTURECHANGED, sent|defwinproc },
8625     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8626     { 0 }
8627 };
8628 static const struct message ml_edit_lbutton_up[] =
8629 {
8630     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
8631     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8632     { WM_CAPTURECHANGED, sent|defwinproc },
8633     { 0 }
8634 };
8635
8636 static WNDPROC old_edit_proc;
8637
8638 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8639 {
8640     static long defwndproc_counter = 0;
8641     LRESULT ret;
8642     struct message msg;
8643
8644     trace("edit: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
8645
8646     /* explicitly ignore WM_GETICON message */
8647     if (message == WM_GETICON) return 0;
8648
8649     /* ignore registered messages */
8650     if (message >= 0xc000) return 0;
8651
8652     msg.message = message;
8653     msg.flags = sent|wparam|lparam;
8654     if (defwndproc_counter) msg.flags |= defwinproc;
8655     msg.wParam = wParam;
8656     msg.lParam = lParam;
8657     add_message(&msg);
8658
8659     defwndproc_counter++;
8660     ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
8661     defwndproc_counter--;
8662
8663     return ret;
8664 }
8665
8666 static void subclass_edit(void)
8667 {
8668     WNDCLASSA cls;
8669
8670     if (!GetClassInfoA(0, "edit", &cls)) assert(0);
8671
8672     old_edit_proc = cls.lpfnWndProc;
8673
8674     cls.hInstance = GetModuleHandle(0);
8675     cls.lpfnWndProc = edit_hook_proc;
8676     cls.lpszClassName = "my_edit_class";
8677     UnregisterClass(cls.lpszClassName, cls.hInstance);
8678     if (!RegisterClassA(&cls)) assert(0);
8679 }
8680
8681 static void test_edit_messages(void)
8682 {
8683     HWND hwnd, parent;
8684     DWORD dlg_code;
8685
8686     subclass_edit();
8687     log_all_parent_messages++;
8688
8689     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8690                              100, 100, 200, 200, 0, 0, 0, NULL);
8691     ok (parent != 0, "Failed to create parent window\n");
8692
8693     /* test single line edit */
8694     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
8695                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
8696     ok(hwnd != 0, "Failed to create edit window\n");
8697
8698     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
8699     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
8700
8701     ShowWindow(hwnd, SW_SHOW);
8702     UpdateWindow(hwnd);
8703     SetFocus(0);
8704     flush_sequence();
8705
8706     SetFocus(hwnd);
8707     ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
8708
8709     SetFocus(0);
8710     ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
8711
8712     SetFocus(0);
8713     ReleaseCapture();
8714     flush_sequence();
8715
8716     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
8717     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
8718
8719     SetFocus(0);
8720     ReleaseCapture();
8721     flush_sequence();
8722
8723     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
8724     ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
8725
8726     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
8727     ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
8728
8729     DestroyWindow(hwnd);
8730
8731     /* test multiline edit */
8732     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
8733                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
8734     ok(hwnd != 0, "Failed to create edit window\n");
8735
8736     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
8737     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
8738        "wrong dlg_code %08x\n", dlg_code);
8739
8740     ShowWindow(hwnd, SW_SHOW);
8741     UpdateWindow(hwnd);
8742     SetFocus(0);
8743     flush_sequence();
8744
8745     SetFocus(hwnd);
8746     ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
8747
8748     SetFocus(0);
8749     ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
8750
8751     SetFocus(0);
8752     ReleaseCapture();
8753     flush_sequence();
8754
8755     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
8756     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
8757
8758     SetFocus(0);
8759     ReleaseCapture();
8760     flush_sequence();
8761
8762     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
8763     ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
8764
8765     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
8766     ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
8767
8768     DestroyWindow(hwnd);
8769     DestroyWindow(parent);
8770
8771     log_all_parent_messages--;
8772 }
8773
8774 /**************************** End of Edit test ******************************/
8775
8776 static const struct message WmKeyDownSkippedSeq[] =
8777 {
8778     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8779     { 0 }
8780 };
8781 static const struct message WmKeyUpSkippedSeq[] =
8782 {
8783     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8784     { 0 }
8785 };
8786
8787 #define EV_STOP 0
8788 #define EV_SENDMSG 1
8789 #define EV_ACK 2
8790
8791 struct peekmsg_info
8792 {
8793     HWND  hwnd;
8794     HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
8795 };
8796
8797 static DWORD CALLBACK send_msg_thread_2(void *param)
8798 {
8799     DWORD ret;
8800     struct peekmsg_info *info = param;
8801
8802     trace("thread: looping\n");
8803     SetEvent(info->hevent[EV_ACK]);
8804
8805     while (1)
8806     {
8807         ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
8808
8809         switch (ret)
8810         {
8811         case WAIT_OBJECT_0 + EV_STOP:
8812             trace("thread: exiting\n");
8813             return 0;
8814
8815         case WAIT_OBJECT_0 + EV_SENDMSG:
8816             trace("thread: sending message\n");
8817             ok( SendNotifyMessageA(info->hwnd, WM_USER, 0, 0),
8818                 "SendNotifyMessageA failed error %u\n", GetLastError());
8819             SetEvent(info->hevent[EV_ACK]);
8820             break;
8821
8822         default:
8823             trace("unexpected return: %04x\n", ret);
8824             assert(0);
8825             break;
8826         }
8827     }
8828     return 0;
8829 }
8830
8831 static void test_PeekMessage(void)
8832 {
8833     MSG msg;
8834     HANDLE hthread;
8835     DWORD tid, qstatus;
8836     UINT qs_all_input = QS_ALLINPUT;
8837     UINT qs_input = QS_INPUT;
8838     BOOL ret;
8839     struct peekmsg_info info;
8840
8841     info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8842                               100, 100, 200, 200, 0, 0, 0, NULL);
8843     assert(info.hwnd);
8844     ShowWindow(info.hwnd, SW_SHOW);
8845     UpdateWindow(info.hwnd);
8846     SetFocus(info.hwnd);
8847
8848     info.hevent[EV_STOP] = CreateEventA(NULL, 0, 0, NULL);
8849     info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
8850     info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
8851
8852     hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
8853     WaitForSingleObject(info.hevent[EV_ACK], 10000);
8854
8855     flush_events();
8856     flush_sequence();
8857
8858     SetLastError(0xdeadbeef);
8859     qstatus = GetQueueStatus(qs_all_input);
8860     if (GetLastError() == ERROR_INVALID_FLAGS)
8861     {
8862         trace("QS_RAWINPUT not supported on this platform\n");
8863         qs_all_input &= ~QS_RAWINPUT;
8864         qs_input &= ~QS_RAWINPUT;
8865     }
8866     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
8867
8868     trace("signalling to send message\n");
8869     SetEvent(info.hevent[EV_SENDMSG]);
8870     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8871
8872     /* pass invalid QS_xxxx flags */
8873     SetLastError(0xdeadbeef);
8874     qstatus = GetQueueStatus(0xffffffff);
8875     ok(qstatus == 0, "GetQueueStatus should fail: %08x\n", qstatus);
8876     ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
8877
8878     qstatus = GetQueueStatus(qs_all_input);
8879     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
8880        "wrong qstatus %08x\n", qstatus);
8881
8882     msg.message = 0;
8883     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8884     ok(!ret,
8885        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8886         msg.message);
8887     ok_sequence(WmUser, "WmUser", FALSE);
8888
8889     qstatus = GetQueueStatus(qs_all_input);
8890     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
8891
8892     keybd_event('N', 0, 0, 0);
8893     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8894     qstatus = GetQueueStatus(qs_all_input);
8895     ok(qstatus == MAKELONG(QS_KEY, QS_KEY),
8896        "wrong qstatus %08x\n", qstatus);
8897
8898     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
8899     qstatus = GetQueueStatus(qs_all_input);
8900     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
8901        "wrong qstatus %08x\n", qstatus);
8902
8903     InvalidateRect(info.hwnd, NULL, FALSE);
8904     qstatus = GetQueueStatus(qs_all_input);
8905     ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8906        "wrong qstatus %08x\n", qstatus);
8907
8908     trace("signalling to send message\n");
8909     SetEvent(info.hevent[EV_SENDMSG]);
8910     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8911
8912     qstatus = GetQueueStatus(qs_all_input);
8913     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8914        "wrong qstatus %08x\n", qstatus);
8915
8916     msg.message = 0;
8917     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
8918     ok(!ret,
8919        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8920         msg.message);
8921     ok_sequence(WmUser, "WmUser", FALSE);
8922
8923     qstatus = GetQueueStatus(qs_all_input);
8924     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8925        "wrong qstatus %08x\n", qstatus);
8926
8927     trace("signalling to send message\n");
8928     SetEvent(info.hevent[EV_SENDMSG]);
8929     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8930
8931     qstatus = GetQueueStatus(qs_all_input);
8932     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8933        "wrong qstatus %08x\n", qstatus);
8934
8935     msg.message = 0;
8936     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
8937     ok(!ret,
8938        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8939         msg.message);
8940     ok_sequence(WmUser, "WmUser", FALSE);
8941
8942     qstatus = GetQueueStatus(qs_all_input);
8943     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8944        "wrong qstatus %08x\n", qstatus);
8945
8946     msg.message = 0;
8947     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
8948     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
8949        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
8950        ret, msg.message, msg.wParam);
8951     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8952
8953     qstatus = GetQueueStatus(qs_all_input);
8954     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
8955        "wrong qstatus %08x\n", qstatus);
8956
8957     msg.message = 0;
8958     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
8959     ok(!ret,
8960        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8961         msg.message);
8962     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8963
8964     qstatus = GetQueueStatus(qs_all_input);
8965     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
8966        "wrong qstatus %08x\n", qstatus);
8967
8968     msg.message = 0;
8969     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
8970     ok(ret && msg.message == WM_PAINT,
8971        "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
8972     DispatchMessageA(&msg);
8973     ok_sequence(WmPaint, "WmPaint", FALSE);
8974
8975     qstatus = GetQueueStatus(qs_all_input);
8976     ok(qstatus == MAKELONG(0, QS_KEY),
8977        "wrong qstatus %08x\n", qstatus);
8978
8979     msg.message = 0;
8980     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
8981     ok(!ret,
8982        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8983         msg.message);
8984     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8985
8986     qstatus = GetQueueStatus(qs_all_input);
8987     ok(qstatus == MAKELONG(0, QS_KEY),
8988        "wrong qstatus %08x\n", qstatus);
8989
8990     trace("signalling to send message\n");
8991     SetEvent(info.hevent[EV_SENDMSG]);
8992     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8993
8994     qstatus = GetQueueStatus(qs_all_input);
8995     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
8996        "wrong qstatus %08x\n", qstatus);
8997
8998     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
8999
9000     qstatus = GetQueueStatus(qs_all_input);
9001     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9002        "wrong qstatus %08x\n", qstatus);
9003
9004     msg.message = 0;
9005     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
9006     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9007        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9008        ret, msg.message, msg.wParam);
9009     ok_sequence(WmUser, "WmUser", FALSE);
9010
9011     qstatus = GetQueueStatus(qs_all_input);
9012     ok(qstatus == MAKELONG(0, QS_KEY),
9013        "wrong qstatus %08x\n", qstatus);
9014
9015     msg.message = 0;
9016     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
9017     ok(!ret,
9018        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9019         msg.message);
9020     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9021
9022     qstatus = GetQueueStatus(qs_all_input);
9023     ok(qstatus == MAKELONG(0, QS_KEY),
9024        "wrong qstatus %08x\n", qstatus);
9025
9026     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9027
9028     qstatus = GetQueueStatus(qs_all_input);
9029     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
9030        "wrong qstatus %08x\n", qstatus);
9031
9032     trace("signalling to send message\n");
9033     SetEvent(info.hevent[EV_SENDMSG]);
9034     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9035
9036     qstatus = GetQueueStatus(qs_all_input);
9037     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9038        "wrong qstatus %08x\n", qstatus);
9039
9040     msg.message = 0;
9041     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
9042     ok(!ret,
9043        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9044         msg.message);
9045     ok_sequence(WmUser, "WmUser", FALSE);
9046
9047     qstatus = GetQueueStatus(qs_all_input);
9048     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
9049        "wrong qstatus %08x\n", qstatus);
9050
9051     msg.message = 0;
9052     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
9053         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
9054     else /* workaround for a missing QS_RAWINPUT support */
9055         ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
9056     ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9057        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9058        ret, msg.message, msg.wParam);
9059     ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
9060
9061     qstatus = GetQueueStatus(qs_all_input);
9062     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
9063        "wrong qstatus %08x\n", qstatus);
9064
9065     msg.message = 0;
9066     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
9067         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
9068     else /* workaround for a missing QS_RAWINPUT support */
9069         ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
9070     ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
9071        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYUP wParam 'N'\n",
9072        ret, msg.message, msg.wParam);
9073     ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
9074
9075     qstatus = GetQueueStatus(qs_all_input);
9076     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9077        "wrong qstatus %08x\n", qstatus);
9078
9079     msg.message = 0;
9080     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
9081     ok(!ret,
9082        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9083         msg.message);
9084     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9085
9086     qstatus = GetQueueStatus(qs_all_input);
9087     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9088        "wrong qstatus %08x\n", qstatus);
9089
9090     msg.message = 0;
9091     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9092     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9093        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9094        ret, msg.message, msg.wParam);
9095     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9096
9097     qstatus = GetQueueStatus(qs_all_input);
9098     ok(qstatus == 0,
9099        "wrong qstatus %08x\n", qstatus);
9100
9101     msg.message = 0;
9102     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9103     ok(!ret,
9104        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9105         msg.message);
9106     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9107
9108     qstatus = GetQueueStatus(qs_all_input);
9109     ok(qstatus == 0,
9110        "wrong qstatus %08x\n", qstatus);
9111
9112     /* test whether presence of the quit flag in the queue affects
9113      * the queue state
9114      */
9115     PostQuitMessage(0x1234abcd);
9116
9117     qstatus = GetQueueStatus(qs_all_input);
9118     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
9119        "wrong qstatus %08x\n", qstatus);
9120
9121     PostMessageA(info.hwnd, WM_USER, 0, 0);
9122
9123     qstatus = GetQueueStatus(qs_all_input);
9124     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
9125        "wrong qstatus %08x\n", qstatus);
9126
9127     msg.message = 0;
9128     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9129     ok(ret && msg.message == WM_USER,
9130        "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
9131     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9132
9133     qstatus = GetQueueStatus(qs_all_input);
9134     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9135        "wrong qstatus %08x\n", qstatus);
9136
9137     msg.message = 0;
9138     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9139     ok(ret && msg.message == WM_QUIT,
9140        "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
9141     ok(msg.wParam == 0x1234abcd, "got wParam %08lx instead of 0x1234abcd\n", msg.wParam);
9142     ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
9143     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9144
9145     qstatus = GetQueueStatus(qs_all_input);
9146 todo_wine {
9147     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9148        "wrong qstatus %08x\n", qstatus);
9149 }
9150
9151     msg.message = 0;
9152     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9153     ok(!ret,
9154        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9155         msg.message);
9156     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9157
9158     qstatus = GetQueueStatus(qs_all_input);
9159     ok(qstatus == 0,
9160        "wrong qstatus %08x\n", qstatus);
9161
9162     trace("signalling to exit\n");
9163     SetEvent(info.hevent[EV_STOP]);
9164
9165     WaitForSingleObject(hthread, INFINITE);
9166
9167     CloseHandle(hthread);
9168     CloseHandle(info.hevent[0]);
9169     CloseHandle(info.hevent[1]);
9170     CloseHandle(info.hevent[2]);
9171
9172     DestroyWindow(info.hwnd);
9173 }
9174
9175 static void wait_move_event(HWND hwnd, int x, int y)
9176 {
9177     MSG msg;
9178     DWORD time;
9179     BOOL  ret;
9180     int go = 0;
9181
9182     time = GetTickCount();
9183     while (GetTickCount() - time < 200 && !go) {
9184         ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9185         go  = ret && msg.pt.x > x && msg.pt.y > y;
9186     }
9187 }
9188
9189 #define STEP 20
9190 static void test_PeekMessage2(void)
9191 {
9192     HWND hwnd;
9193     BOOL ret;
9194     MSG msg;
9195     UINT message;
9196     DWORD time1, time2, time3;
9197     int x1, y1, x2, y2, x3, y3;
9198     POINT pos;
9199
9200     time1 = time2 = time3 = 0;
9201     x1 = y1 = x2 = y2 = x3 = y3 = 0;
9202
9203     /* Initialise window and make sure it is ready for events */
9204     hwnd = CreateWindow("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
9205                         10, 10, 800, 800, NULL, NULL, NULL, NULL);
9206     assert(hwnd);
9207     trace("Window for test_PeekMessage2 %p\n", hwnd);
9208     ShowWindow(hwnd, SW_SHOW);
9209     UpdateWindow(hwnd);
9210     SetFocus(hwnd);
9211     GetCursorPos(&pos);
9212     SetCursorPos(100, 100);
9213     mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
9214     flush_events();
9215
9216     /* Do initial mousemove, wait until we can see it
9217        and then do our test peek with PM_NOREMOVE. */
9218     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
9219     wait_move_event(hwnd, 80, 80);
9220
9221     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9222     ok(ret, "no message available\n");
9223     if (ret) {
9224         trace("1st move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
9225         message = msg.message;
9226         time1 = msg.time;
9227         x1 = msg.pt.x;
9228         y1 = msg.pt.y;
9229         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
9230     }
9231
9232     /* Allow time to advance a bit, and then simulate the user moving their
9233      * mouse around. After that we peek again with PM_NOREMOVE.
9234      * Although the previous mousemove message was never removed, the
9235      * mousemove we now peek should reflect the recent mouse movements
9236      * because the input queue will merge the move events. */
9237     Sleep(2);
9238     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
9239     wait_move_event(hwnd, x1, y1);
9240
9241     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9242     ok(ret, "no message available\n");
9243     if (ret) {
9244         trace("2nd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
9245         message = msg.message;
9246         time2 = msg.time;
9247         x2 = msg.pt.x;
9248         y2 = msg.pt.y;
9249         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
9250         ok(time2 > time1, "message time not advanced: %x %x\n", time1, time2);
9251         ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
9252     }
9253
9254     /* Have another go, to drive the point home */
9255     Sleep(2);
9256     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
9257     wait_move_event(hwnd, x2, y2);
9258
9259     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9260     ok(ret, "no message available\n");
9261     if (ret) {
9262         trace("3rd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
9263         message = msg.message;
9264         time3 = msg.time;
9265         x3 = msg.pt.x;
9266         y3 = msg.pt.y;
9267         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
9268         ok(time3 > time2, "message time not advanced: %x %x\n", time2, time3);
9269         ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
9270     }
9271
9272     DestroyWindow(hwnd);
9273     SetCursorPos(pos.x, pos.y);
9274     flush_events();
9275 }
9276
9277 static void test_quit_message(void)
9278 {
9279     MSG msg;
9280     BOOL ret;
9281
9282     /* test using PostQuitMessage */
9283     flush_events();
9284     PostQuitMessage(0xbeef);
9285
9286     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
9287     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
9288     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9289     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
9290
9291     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
9292     ok(ret, "PostMessage failed with error %d\n", GetLastError());
9293
9294     ret = GetMessage(&msg, NULL, 0, 0);
9295     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
9296     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
9297
9298     /* note: WM_QUIT message received after WM_USER message */
9299     ret = GetMessage(&msg, NULL, 0, 0);
9300     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
9301     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9302     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
9303
9304     ret = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
9305     ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
9306
9307     /* now test with PostThreadMessage - different behaviour! */
9308     PostThreadMessage(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
9309
9310     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
9311     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
9312     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9313     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
9314
9315     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
9316     ok(ret, "PostMessage failed with error %d\n", GetLastError());
9317
9318     /* note: we receive the WM_QUIT message first this time */
9319     ret = GetMessage(&msg, NULL, 0, 0);
9320     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
9321     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9322     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
9323
9324     ret = GetMessage(&msg, NULL, 0, 0);
9325     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
9326     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
9327 }
9328
9329 static const struct message WmMouseHoverSeq[] = {
9330     { WM_MOUSEACTIVATE, sent|optional },  /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
9331     { WM_MOUSEACTIVATE, sent|optional },
9332     { WM_TIMER, sent|optional }, /* XP sends it */
9333     { WM_SYSTIMER, sent },
9334     { WM_MOUSEHOVER, sent|wparam, 0 },
9335     { 0 }
9336 };
9337
9338 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
9339 {
9340     MSG msg;
9341     DWORD start_ticks, end_ticks;
9342
9343     start_ticks = GetTickCount();
9344     /* add some deviation (5%) to cover not expected delays */
9345     start_ticks += timeout / 20;
9346
9347     do
9348     {
9349         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
9350         {
9351             /* Timer proc messages are not dispatched to the window proc,
9352              * and therefore not logged.
9353              */
9354             if (msg.message == WM_TIMER || msg.message == WM_SYSTIMER)
9355             {
9356                 struct message s_msg;
9357
9358                 s_msg.message = msg.message;
9359                 s_msg.flags = sent|wparam|lparam;
9360                 s_msg.wParam = msg.wParam;
9361                 s_msg.lParam = msg.lParam;
9362                 add_message(&s_msg);
9363             }
9364             DispatchMessage(&msg);
9365         }
9366
9367         end_ticks = GetTickCount();
9368
9369         /* inject WM_MOUSEMOVE to see how it changes tracking */
9370         if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
9371         {
9372             mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
9373             mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
9374
9375             inject_mouse_move = FALSE;
9376         }
9377     } while (start_ticks + timeout >= end_ticks);
9378 }
9379
9380 static void test_TrackMouseEvent(void)
9381 {
9382     TRACKMOUSEEVENT tme;
9383     BOOL ret;
9384     HWND hwnd, hchild;
9385     RECT rc_parent, rc_child;
9386     UINT default_hover_time, hover_width = 0, hover_height = 0;
9387
9388 #define track_hover(track_hwnd, track_hover_time) \
9389     tme.cbSize = sizeof(tme); \
9390     tme.dwFlags = TME_HOVER; \
9391     tme.hwndTrack = track_hwnd; \
9392     tme.dwHoverTime = track_hover_time; \
9393     SetLastError(0xdeadbeef); \
9394     ret = pTrackMouseEvent(&tme); \
9395     ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
9396
9397 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
9398     tme.cbSize = sizeof(tme); \
9399     tme.dwFlags = TME_QUERY; \
9400     tme.hwndTrack = (HWND)0xdeadbeef; \
9401     tme.dwHoverTime = 0xdeadbeef; \
9402     SetLastError(0xdeadbeef); \
9403     ret = pTrackMouseEvent(&tme); \
9404     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
9405     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
9406     ok(tme.dwFlags == (expected_track_flags), \
9407        "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
9408     ok(tme.hwndTrack == (expected_track_hwnd), \
9409        "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
9410     ok(tme.dwHoverTime == (expected_hover_time), \
9411        "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
9412
9413 #define track_hover_cancel(track_hwnd) \
9414     tme.cbSize = sizeof(tme); \
9415     tme.dwFlags = TME_HOVER | TME_CANCEL; \
9416     tme.hwndTrack = track_hwnd; \
9417     tme.dwHoverTime = 0xdeadbeef; \
9418     SetLastError(0xdeadbeef); \
9419     ret = pTrackMouseEvent(&tme); \
9420     ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
9421
9422     default_hover_time = 0xdeadbeef;
9423     SetLastError(0xdeadbeef);
9424     ret = SystemParametersInfo(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
9425     ok(ret, "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
9426     if (!ret) default_hover_time = 400;
9427     trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
9428
9429     SetLastError(0xdeadbeef);
9430     ret = SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
9431     ok(ret, "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
9432     if (!ret) hover_width = 4;
9433     SetLastError(0xdeadbeef);
9434     ret = SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
9435     ok(ret, "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
9436     if (!ret) hover_height = 4;
9437     trace("hover rect is %u x %d\n", hover_width, hover_height);
9438
9439     hwnd = CreateWindowEx(0, "TestWindowClass", NULL,
9440                           WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9441                           CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
9442                           NULL, NULL, 0);
9443     assert(hwnd);
9444
9445     hchild = CreateWindowEx(0, "TestWindowClass", NULL,
9446                           WS_CHILD | WS_BORDER | WS_VISIBLE,
9447                           50, 50, 200, 200, hwnd,
9448                           NULL, NULL, 0);
9449     assert(hchild);
9450
9451     SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
9452     flush_events();
9453     flush_sequence();
9454
9455     tme.cbSize = 0;
9456     tme.dwFlags = TME_QUERY;
9457     tme.hwndTrack = (HWND)0xdeadbeef;
9458     tme.dwHoverTime = 0xdeadbeef;
9459     SetLastError(0xdeadbeef);
9460     ret = pTrackMouseEvent(&tme);
9461     ok(!ret, "TrackMouseEvent should fail\n");
9462     ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef),
9463        "not expected error %u\n", GetLastError());
9464
9465     tme.cbSize = sizeof(tme);
9466     tme.dwFlags = TME_HOVER;
9467     tme.hwndTrack = (HWND)0xdeadbeef;
9468     tme.dwHoverTime = 0xdeadbeef;
9469     SetLastError(0xdeadbeef);
9470     ret = pTrackMouseEvent(&tme);
9471     ok(!ret, "TrackMouseEvent should fail\n");
9472     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
9473        "not expected error %u\n", GetLastError());
9474
9475     tme.cbSize = sizeof(tme);
9476     tme.dwFlags = TME_HOVER | TME_CANCEL;
9477     tme.hwndTrack = (HWND)0xdeadbeef;
9478     tme.dwHoverTime = 0xdeadbeef;
9479     SetLastError(0xdeadbeef);
9480     ret = pTrackMouseEvent(&tme);
9481     ok(!ret, "TrackMouseEvent should fail\n");
9482     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
9483        "not expected error %u\n", GetLastError());
9484
9485     GetWindowRect(hwnd, &rc_parent);
9486     GetWindowRect(hchild, &rc_child);
9487     SetCursorPos(rc_child.left - 10, rc_child.top - 10);
9488
9489     /* Process messages so that the system updates its internal current
9490      * window and hittest, otherwise TrackMouseEvent calls don't have any
9491      * effect.
9492      */
9493     flush_events();
9494     flush_sequence();
9495
9496     track_query(0, NULL, 0);
9497     track_hover(hchild, 0);
9498     track_query(0, NULL, 0);
9499
9500     flush_events();
9501     flush_sequence();
9502
9503     track_hover(hwnd, 0);
9504     track_query(TME_HOVER, hwnd, default_hover_time);
9505
9506     pump_msg_loop_timeout(default_hover_time, FALSE);
9507     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
9508
9509     track_query(0, NULL, 0);
9510
9511     track_hover(hwnd, HOVER_DEFAULT);
9512     track_query(TME_HOVER, hwnd, default_hover_time);
9513
9514     Sleep(default_hover_time / 2);
9515     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
9516     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
9517
9518     track_query(TME_HOVER, hwnd, default_hover_time);
9519
9520     pump_msg_loop_timeout(default_hover_time / 2, FALSE);
9521     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
9522
9523     track_query(0, NULL, 0);
9524
9525     track_hover(hwnd, HOVER_DEFAULT);
9526     track_query(TME_HOVER, hwnd, default_hover_time);
9527
9528     pump_msg_loop_timeout(default_hover_time, TRUE);
9529     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
9530
9531     track_query(0, NULL, 0);
9532
9533     track_hover(hwnd, HOVER_DEFAULT);
9534     track_query(TME_HOVER, hwnd, default_hover_time);
9535     track_hover_cancel(hwnd);
9536
9537     DestroyWindow(hwnd);
9538
9539 #undef track_hover
9540 #undef track_query
9541 #undef track_hover_cancel
9542 }
9543
9544
9545 static const struct message WmSetWindowRgn[] = {
9546     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
9547     { WM_NCCALCSIZE, sent|wparam, 1 },
9548     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
9549     { WM_GETTEXT, sent|defwinproc|optional },
9550     { WM_ERASEBKGND, sent|optional },
9551     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
9552     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9553     { 0 }
9554 };
9555
9556 static const struct message WmSetWindowRgn_no_redraw[] = {
9557     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
9558     { WM_NCCALCSIZE, sent|wparam, 1 },
9559     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
9560     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9561     { 0 }
9562 };
9563
9564 static const struct message WmSetWindowRgn_clear[] = {
9565     { WM_WINDOWPOSCHANGING, sent/*|wparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */ },
9566     { WM_NCCALCSIZE, sent|wparam, 1 },
9567     { WM_NCPAINT, sent|optional },
9568     { WM_GETTEXT, sent|defwinproc|optional },
9569     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
9570     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
9571     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
9572     { WM_NCPAINT, sent|optional },
9573     { WM_GETTEXT, sent|defwinproc|optional },
9574     { WM_ERASEBKGND, sent|optional },
9575     { WM_WINDOWPOSCHANGING, sent|optional },
9576     { WM_NCCALCSIZE, sent|optional|wparam, 1 },
9577     { WM_NCPAINT, sent|optional },
9578     { WM_GETTEXT, sent|defwinproc|optional },
9579     { WM_ERASEBKGND, sent|optional },
9580     { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
9581     { WM_NCCALCSIZE, sent|optional|wparam, 1 },
9582     { WM_NCPAINT, sent|optional },
9583     { WM_GETTEXT, sent|defwinproc|optional },
9584     { WM_ERASEBKGND, sent|optional },
9585     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9586     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9587     { 0 }
9588 };
9589
9590 static void test_SetWindowRgn(void)
9591 {
9592     HRGN hrgn;
9593     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
9594                                 100, 100, 200, 200, 0, 0, 0, NULL);
9595     ok( hwnd != 0, "Failed to create overlapped window\n" );
9596
9597     ShowWindow( hwnd, SW_SHOW );
9598     UpdateWindow( hwnd );
9599     flush_events();
9600     flush_sequence();
9601
9602     trace("testing SetWindowRgn\n");
9603     hrgn = CreateRectRgn( 0, 0, 150, 150 );
9604     SetWindowRgn( hwnd, hrgn, TRUE );
9605     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
9606
9607     hrgn = CreateRectRgn( 30, 30, 160, 160 );
9608     SetWindowRgn( hwnd, hrgn, FALSE );
9609     ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
9610
9611     hrgn = CreateRectRgn( 0, 0, 180, 180 );
9612     SetWindowRgn( hwnd, hrgn, TRUE );
9613     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
9614
9615     SetWindowRgn( hwnd, 0, TRUE );
9616     ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
9617
9618     DestroyWindow( hwnd );
9619 }
9620
9621 /*************************** ShowWindow() test ******************************/
9622 static const struct message WmShowNormal[] = {
9623     { WM_SHOWWINDOW, sent|wparam, 1 },
9624     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9625     { HCBT_ACTIVATE, hook },
9626     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
9627     { HCBT_SETFOCUS, hook },
9628     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9629     { 0 }
9630 };
9631 static const struct message WmShow[] = {
9632     { WM_SHOWWINDOW, sent|wparam, 1 },
9633     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9634     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9635     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9636     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9637     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9638     { 0 }
9639 };
9640 static const struct message WmShowNoActivate_1[] = {
9641     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
9642     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
9643     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
9644     { WM_MOVE, sent|defwinproc },
9645     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9646     { 0 }
9647 };
9648 static const struct message WmShowNoActivate_2[] = {
9649     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
9650     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9651     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9652     { WM_MOVE, sent|defwinproc },
9653     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9654     { HCBT_SETFOCUS, hook|optional },
9655     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
9656     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
9657     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
9658     { 0 }
9659 };
9660 static const struct message WmShowNA_1[] = {
9661     { WM_SHOWWINDOW, sent|wparam, 1 },
9662     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
9663     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9664     { 0 }
9665 };
9666 static const struct message WmShowNA_2[] = {
9667     { WM_SHOWWINDOW, sent|wparam, 1 },
9668     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
9669     { 0 }
9670 };
9671 static const struct message WmRestore_1[] = {
9672     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
9673     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9674     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9675     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9676     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9677     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9678     { WM_MOVE, sent|defwinproc },
9679     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9680     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
9681     { 0 }
9682 };
9683 static const struct message WmRestore_2[] = {
9684     { WM_SHOWWINDOW, sent|wparam, 1 },
9685     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9686     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9687     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9688     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9689     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9690     { 0 }
9691 };
9692 static const struct message WmRestore_3[] = {
9693     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
9694     { WM_GETMINMAXINFO, sent },
9695     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9696     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
9697     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
9698     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
9699     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9700     { WM_MOVE, sent|defwinproc },
9701     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
9702     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
9703     { 0 }
9704 };
9705 static const struct message WmRestore_4[] = {
9706     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
9707     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
9708     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
9709     { WM_MOVE, sent|defwinproc },
9710     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9711     { 0 }
9712 };
9713 static const struct message WmRestore_5[] = {
9714     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
9715     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
9716     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
9717     { WM_MOVE, sent|defwinproc },
9718     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9719     { 0 }
9720 };
9721 static const struct message WmHide_1[] = {
9722     { WM_SHOWWINDOW, sent|wparam, 0 },
9723     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9724     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9725     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
9726     { 0 }
9727 };
9728 static const struct message WmHide_2[] = {
9729     { WM_SHOWWINDOW, sent|wparam, 0 },
9730     { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
9731     { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
9732     { 0 }
9733 };
9734 static const struct message WmHide_3[] = {
9735     { WM_SHOWWINDOW, sent|wparam, 0 },
9736     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9737     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9738     { HCBT_SETFOCUS, hook|optional },
9739     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9740     { 0 }
9741 };
9742 static const struct message WmShowMinimized_1[] = {
9743     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
9744     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9745     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9746     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9747     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9748     { WM_MOVE, sent|defwinproc },
9749     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
9750     { 0 }
9751 };
9752 static const struct message WmMinimize_1[] = {
9753     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
9754     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9755     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9756     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9757     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9758     { WM_MOVE, sent|defwinproc },
9759     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
9760     { 0 }
9761 };
9762 static const struct message WmMinimize_2[] = {
9763     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
9764     { HCBT_SETFOCUS, hook|optional },
9765     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9766     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9767     { WM_MOVE, sent|defwinproc },
9768     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
9769     { 0 }
9770 };
9771 static const struct message WmMinimize_3[] = {
9772     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
9773     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9774     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9775     { WM_MOVE, sent|defwinproc },
9776     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
9777     { 0 }
9778 };
9779 static const struct message WmShowMinNoActivate[] = {
9780     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
9781     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
9782     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9783     { 0 }
9784 };
9785 static const struct message WmMinMax_1[] = {
9786     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
9787     { 0 }
9788 };
9789 static const struct message WmMinMax_2[] = {
9790     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
9791     { 0 }
9792 };
9793 static const struct message WmMinMax_3[] = {
9794     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
9795     { 0 }
9796 };
9797 static const struct message WmMinMax_4[] = {
9798     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
9799     { 0 }
9800 };
9801 static const struct message WmShowMaximized_1[] = {
9802     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
9803     { WM_GETMINMAXINFO, sent },
9804     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9805     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9806     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9807     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9808     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9809     { WM_MOVE, sent|defwinproc },
9810     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
9811     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
9812     { 0 }
9813 };
9814 static const struct message WmShowMaximized_2[] = {
9815     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
9816     { WM_GETMINMAXINFO, sent },
9817     { WM_WINDOWPOSCHANGING, sent|optional },
9818     { HCBT_ACTIVATE, hook|optional },
9819     { WM_WINDOWPOSCHANGED, sent|optional },
9820     { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
9821     { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
9822     { WM_WINDOWPOSCHANGING, sent },
9823     { HCBT_SETFOCUS, hook|optional },
9824     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9825     { WM_MOVE, sent|defwinproc },
9826     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
9827     { HCBT_SETFOCUS, hook|optional },
9828     { 0 }
9829 };
9830 static const struct message WmShowMaximized_3[] = {
9831     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
9832     { WM_GETMINMAXINFO, sent },
9833     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
9834     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9835     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9836     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9837     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
9838     { WM_MOVE, sent|defwinproc },
9839     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
9840     { 0 }
9841 };
9842
9843 static void test_ShowWindow(void)
9844 {
9845     /* ShowWindow commands in random order */
9846     static const struct
9847     {
9848         INT cmd; /* ShowWindow command */
9849         LPARAM ret; /* ShowWindow return value */
9850         DWORD style; /* window style after the command */
9851         const struct message *msg; /* message sequence the command produces */
9852         BOOL todo_msg; /* message sequence doesn't match what Wine does */
9853     } sw[] =
9854     {
9855 /*  1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal, FALSE },
9856 /*  2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9857 /*  3 */ { SW_HIDE, TRUE, 0, WmHide_1, FALSE },
9858 /*  4 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
9859 /*  5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1, FALSE },
9860 /*  6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1, FALSE },
9861 /*  7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1, FALSE },
9862 /*  8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
9863 /*  9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1, FALSE },
9864 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2, FALSE },
9865 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1, FALSE },
9866 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq, FALSE },
9867 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1, FALSE },
9868 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9869 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2, FALSE },
9870 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
9871 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow, FALSE },
9872 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9873 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1, FALSE },
9874 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
9875 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
9876 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate, TRUE },
9877 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4, FALSE },
9878 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
9879 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
9880 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1, FALSE },
9881 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2, FALSE },
9882 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
9883 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
9884 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1, FALSE },
9885 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9886 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3, FALSE },
9887 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
9888 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, FALSE }, /* what does this mean?! */
9889 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, FALSE },
9890 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
9891 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2, FALSE },
9892 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9893 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9894 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2, FALSE },
9895 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
9896 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2, TRUE },
9897 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2, FALSE },
9898 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1, FALSE },
9899 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
9900 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3, FALSE },
9901 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4, FALSE },
9902 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3, FALSE },
9903 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq, FALSE },
9904 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5, FALSE },
9905 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9906 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1, FALSE },
9907 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
9908 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3, FALSE },
9909 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
9910 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2, FALSE },
9911 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq, FALSE }
9912     };
9913     HWND hwnd;
9914     DWORD style;
9915     LPARAM ret;
9916     INT i;
9917
9918 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
9919     hwnd = CreateWindowEx(0, "ShowWindowClass", NULL, WS_BASE,
9920                           120, 120, 90, 90,
9921                           0, 0, 0, NULL);
9922     assert(hwnd);
9923
9924     style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
9925     ok(style == 0, "expected style 0, got %08x\n", style);
9926
9927     flush_events();
9928     flush_sequence();
9929
9930     for (i = 0; i < sizeof(sw)/sizeof(sw[0]); i++)
9931     {
9932         static const char * const sw_cmd_name[13] =
9933         {
9934             "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
9935             "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
9936             "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
9937             "SW_NORMALNA" /* 0xCC */
9938         };
9939         char comment[64];
9940         INT idx; /* index into the above array of names */
9941
9942         idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
9943
9944         style = GetWindowLong(hwnd, GWL_STYLE);
9945         trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
9946         ret = ShowWindow(hwnd, sw[i].cmd);
9947         ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
9948         style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
9949         ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
9950
9951         sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
9952         ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
9953
9954         flush_events();
9955         flush_sequence();
9956     }
9957
9958     DestroyWindow(hwnd);
9959 }
9960
9961 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9962 {
9963     struct message msg;
9964
9965     trace("dialog: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
9966
9967     switch (message)
9968     {
9969     case WM_WINDOWPOSCHANGING:
9970     case WM_WINDOWPOSCHANGED:
9971     {
9972         WINDOWPOS *winpos = (WINDOWPOS *)lParam;
9973
9974         trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
9975         trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
9976               winpos->hwnd, winpos->hwndInsertAfter,
9977               winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
9978         dump_winpos_flags(winpos->flags);
9979
9980         /* Log only documented flags, win2k uses 0x1000 and 0x2000
9981          * in the high word for internal purposes
9982          */
9983         wParam = winpos->flags & 0xffff;
9984         /* We are not interested in the flags that don't match under XP and Win9x */
9985         wParam &= ~(SWP_NOZORDER);
9986         break;
9987     }
9988
9989     /* explicitly ignore WM_GETICON message */
9990     case WM_GETICON:
9991         return 0;
9992     }
9993
9994     msg.message = message;
9995     msg.flags = sent|wparam|lparam;
9996     msg.wParam = wParam;
9997     msg.lParam = lParam;
9998     add_message(&msg);
9999
10000     /* calling DefDlgProc leads to a recursion under XP */
10001
10002     switch (message)
10003     {
10004     case WM_INITDIALOG:
10005     case WM_GETDLGCODE:
10006         return 0;
10007     }
10008     return 1;
10009 }
10010
10011 static const struct message WmDefDlgSetFocus_1[] = {
10012     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
10013     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
10014     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
10015     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
10016     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
10017     { HCBT_SETFOCUS, hook },
10018     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
10019     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10020     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10021     { WM_SETFOCUS, sent|wparam, 0 },
10022     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
10023     { WM_CTLCOLOREDIT, sent },
10024     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
10025     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10026     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10027     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10028     { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
10029     { 0 }
10030 };
10031 static const struct message WmDefDlgSetFocus_2[] = {
10032     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
10033     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
10034     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
10035     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
10036     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
10037     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10038     { WM_CTLCOLOREDIT, sent|optional }, /* XP */
10039     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10040     { 0 }
10041 };
10042 /* Creation of a dialog */
10043 static const struct message WmCreateDialogParamSeq_1[] = {
10044     { HCBT_CREATEWND, hook },
10045     { WM_NCCREATE, sent },
10046     { WM_NCCALCSIZE, sent|wparam, 0 },
10047     { WM_CREATE, sent },
10048     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
10049     { WM_SIZE, sent|wparam, SIZE_RESTORED },
10050     { WM_MOVE, sent },
10051     { WM_SETFONT, sent },
10052     { WM_INITDIALOG, sent },
10053     { WM_CHANGEUISTATE, sent|optional },
10054     { 0 }
10055 };
10056 /* Creation of a dialog */
10057 static const struct message WmCreateDialogParamSeq_2[] = {
10058     { HCBT_CREATEWND, hook },
10059     { WM_NCCREATE, sent },
10060     { WM_NCCALCSIZE, sent|wparam, 0 },
10061     { WM_CREATE, sent },
10062     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
10063     { WM_SIZE, sent|wparam, SIZE_RESTORED },
10064     { WM_MOVE, sent },
10065     { WM_CHANGEUISTATE, sent|optional },
10066     { 0 }
10067 };
10068
10069 static void test_dialog_messages(void)
10070 {
10071     WNDCLASS cls;
10072     HWND hdlg, hedit1, hedit2, hfocus;
10073     LRESULT ret;
10074
10075 #define set_selection(hctl, start, end) \
10076     ret = SendMessage(hctl, EM_SETSEL, start, end); \
10077     ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
10078
10079 #define check_selection(hctl, start, end) \
10080     ret = SendMessage(hctl, EM_GETSEL, 0, 0); \
10081     ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
10082
10083     subclass_edit();
10084
10085     hdlg = CreateWindowEx(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
10086                           WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
10087                           0, 0, 100, 100, 0, 0, 0, NULL);
10088     ok(hdlg != 0, "Failed to create custom dialog window\n");
10089
10090     hedit1 = CreateWindowEx(0, "my_edit_class", NULL,
10091                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
10092                            0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
10093     ok(hedit1 != 0, "Failed to create edit control\n");
10094     hedit2 = CreateWindowEx(0, "my_edit_class", NULL,
10095                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
10096                            0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
10097     ok(hedit2 != 0, "Failed to create edit control\n");
10098
10099     SendMessage(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
10100     SendMessage(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
10101
10102     hfocus = GetFocus();
10103     ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
10104
10105     SetFocus(hedit2);
10106     hfocus = GetFocus();
10107     ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
10108
10109     check_selection(hedit1, 0, 0);
10110     check_selection(hedit2, 0, 0);
10111
10112     set_selection(hedit2, 0, -1);
10113     check_selection(hedit2, 0, 3);
10114
10115     SetFocus(0);
10116     hfocus = GetFocus();
10117     ok(hfocus == 0, "wrong focus %p\n", hfocus);
10118
10119     flush_sequence();
10120     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
10121     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
10122     ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
10123
10124     hfocus = GetFocus();
10125     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
10126
10127     check_selection(hedit1, 0, 5);
10128     check_selection(hedit2, 0, 3);
10129
10130     flush_sequence();
10131     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
10132     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
10133     ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
10134
10135     hfocus = GetFocus();
10136     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
10137
10138     check_selection(hedit1, 0, 5);
10139     check_selection(hedit2, 0, 3);
10140
10141     EndDialog(hdlg, 0);
10142     DestroyWindow(hedit1);
10143     DestroyWindow(hedit2);
10144     DestroyWindow(hdlg);
10145     flush_sequence();
10146
10147 #undef set_selection
10148 #undef check_selection
10149
10150     ok(GetClassInfo(0, "#32770", &cls), "GetClassInfo failed\n");
10151     cls.lpszClassName = "MyDialogClass";
10152     cls.hInstance = GetModuleHandle(0);
10153     /* need a cast since a dlgproc is used as a wndproc */
10154     cls.lpfnWndProc = (WNDPROC)test_dlg_proc;
10155     if (!RegisterClass(&cls)) assert(0);
10156
10157     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
10158     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
10159     ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
10160     EndDialog(hdlg, 0);
10161     DestroyWindow(hdlg);
10162     flush_sequence();
10163
10164     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
10165     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
10166     ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
10167     EndDialog(hdlg, 0);
10168     DestroyWindow(hdlg);
10169     flush_sequence();
10170
10171     UnregisterClass(cls.lpszClassName, cls.hInstance);
10172 }
10173
10174 static void test_nullCallback(void)
10175 {
10176     HWND hwnd;
10177
10178     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
10179                            100, 100, 200, 200, 0, 0, 0, NULL);
10180     ok (hwnd != 0, "Failed to create overlapped window\n");
10181
10182     SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
10183     flush_events();
10184     DestroyWindow(hwnd);
10185 }
10186
10187 /* SetActiveWindow( 0 ) hwnd visible */
10188 static const struct message SetActiveWindowSeq0[] =
10189 {
10190     { HCBT_ACTIVATE, hook },
10191     { WM_NCACTIVATE, sent|wparam, 0 },
10192     { WM_GETTEXT, sent|defwinproc|optional },
10193     { WM_ACTIVATE, sent|wparam, 0 },
10194     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10195     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10196     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
10197     { WM_NCACTIVATE, sent|wparam, 1 },
10198     { WM_GETTEXT, sent|defwinproc|optional },
10199     { WM_ACTIVATE, sent|wparam, 1 },
10200     { HCBT_SETFOCUS, hook },
10201     { WM_KILLFOCUS, sent|defwinproc },
10202     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
10203     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10204     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
10205     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10206     { WM_SETFOCUS, sent|defwinproc },
10207     { 0 }
10208 };
10209 /* SetActiveWindow( hwnd ) hwnd visible */
10210 static const struct message SetActiveWindowSeq1[] =
10211 {
10212     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10213     { 0 }
10214 };
10215 /* SetActiveWindow( popup ) hwnd visible, popup visible */
10216 static const struct message SetActiveWindowSeq2[] =
10217 {
10218     { HCBT_ACTIVATE, hook },
10219     { WM_NCACTIVATE, sent|wparam, 0 },
10220     { WM_GETTEXT, sent|defwinproc|optional },
10221     { WM_ACTIVATE, sent|wparam, 0 },
10222     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10223     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
10224     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10225     { WM_NCPAINT, sent|optional },
10226     { WM_GETTEXT, sent|defwinproc|optional },
10227     { WM_ERASEBKGND, sent|optional },
10228     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10229     { WM_NCACTIVATE, sent|wparam, 1 },
10230     { WM_GETTEXT, sent|defwinproc|optional },
10231     { WM_ACTIVATE, sent|wparam, 1 },
10232     { HCBT_SETFOCUS, hook },
10233     { WM_KILLFOCUS, sent|defwinproc },
10234     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
10235     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10236     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
10237     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10238     { WM_SETFOCUS, sent|defwinproc },
10239     { 0 }
10240 };
10241
10242 /* SetActiveWindow( hwnd ) hwnd not visible */
10243 static const struct message SetActiveWindowSeq3[] =
10244 {
10245     { HCBT_ACTIVATE, hook },
10246     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10247     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10248     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
10249     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10250     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10251     { WM_ACTIVATEAPP, sent|wparam, 1 },
10252     { WM_ACTIVATEAPP, sent|wparam, 1 },
10253     { WM_NCACTIVATE, sent|wparam, 1 },
10254     { WM_ACTIVATE, sent|wparam, 1 },
10255     { HCBT_SETFOCUS, hook },
10256     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10257     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10258     { WM_SETFOCUS, sent|defwinproc },
10259     { 0 }
10260 };
10261 /* SetActiveWindow( popup ) hwnd not visible, popup not visible */
10262 static const struct message SetActiveWindowSeq4[] =
10263 {
10264     { HCBT_ACTIVATE, hook },
10265     { WM_NCACTIVATE, sent|wparam, 0 },
10266     { WM_GETTEXT, sent|defwinproc|optional },
10267     { WM_ACTIVATE, sent|wparam, 0 },
10268     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10269     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
10270     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10271     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10272     { WM_NCACTIVATE, sent|wparam, 1 },
10273     { WM_GETTEXT, sent|defwinproc|optional },
10274     { WM_ACTIVATE, sent|wparam, 1 },
10275     { HCBT_SETFOCUS, hook },
10276     { WM_KILLFOCUS, sent|defwinproc },
10277     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
10278     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10279     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
10280     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10281     { WM_SETFOCUS, sent|defwinproc },
10282     { 0 }
10283 };
10284
10285
10286 static void test_SetActiveWindow(void)
10287 {
10288     HWND hwnd, popup, ret;
10289
10290     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
10291                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10292                            100, 100, 200, 200, 0, 0, 0, NULL);
10293
10294     popup = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
10295                            WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_POPUP,
10296                            100, 100, 200, 200, hwnd, 0, 0, NULL);
10297
10298     ok(hwnd != 0, "Failed to create overlapped window\n");
10299     flush_sequence();
10300
10301     ok(popup != 0, "Failed to create popup window\n");
10302     flush_sequence();
10303
10304     trace("SetActiveWindow(0)\n");
10305     ret = SetActiveWindow(0);
10306     ok( ret == popup, "Failed to SetActiveWindow(0)\n");
10307     ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", TRUE);
10308     flush_sequence();
10309
10310     trace("SetActiveWindow(hwnd), hwnd visible\n");
10311     ret = SetActiveWindow(hwnd);
10312     todo_wine
10313     {
10314         ok( ret == hwnd, "Failed to SetActiveWindow(hwnd), hwnd visible\n");
10315     }
10316     ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE);
10317     flush_sequence();
10318
10319     trace("SetActiveWindow(popup), hwnd visible, popup visible\n");
10320     ret = SetActiveWindow(popup);
10321     ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n");
10322     ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visible", FALSE);
10323     flush_sequence();
10324
10325     ShowWindow(hwnd, SW_HIDE);
10326     ShowWindow(popup, SW_HIDE);
10327     flush_sequence();
10328
10329     trace("SetActiveWindow(hwnd), hwnd not visible\n");
10330     ret = SetActiveWindow(hwnd);
10331     ok( ret == NULL, "Failed to SetActiveWindow(hwnd), hwnd not visible\n");
10332     ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE);
10333     flush_sequence();
10334
10335     trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n");
10336     ret = SetActiveWindow(popup);
10337     ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n");
10338     ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visible", TRUE);
10339     flush_sequence();
10340
10341     trace("done\n");
10342
10343     DestroyWindow(hwnd);
10344 }
10345
10346 static const struct message SetForegroundWindowSeq[] =
10347 {
10348     { WM_NCACTIVATE, sent|wparam, 0 },
10349     { WM_GETTEXT, sent|defwinproc|optional },
10350     { WM_ACTIVATE, sent|wparam, 0 },
10351     { WM_ACTIVATEAPP, sent|wparam, 0 },
10352     { WM_KILLFOCUS, sent },
10353     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
10354     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
10355     { 0 }
10356 };
10357
10358 static void test_SetForegroundWindow(void)
10359 {
10360     HWND hwnd;
10361
10362     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
10363                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10364                            100, 100, 200, 200, 0, 0, 0, NULL);
10365     ok (hwnd != 0, "Failed to create overlapped window\n");
10366     flush_sequence();
10367
10368     trace("SetForegroundWindow( 0 )\n");
10369     SetForegroundWindow( 0 );
10370     ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
10371     trace("SetForegroundWindow( GetDesktopWindow() )\n");
10372     SetForegroundWindow( GetDesktopWindow() );
10373     ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
10374                                         "foreground top level window", FALSE);
10375     trace("done\n");
10376
10377     DestroyWindow(hwnd);
10378 }
10379
10380 static void test_dbcs_wm_char(void)
10381 {
10382     BYTE dbch[2];
10383     WCHAR wch, bad_wch;
10384     HWND hwnd, hwnd2;
10385     MSG msg;
10386     DWORD time;
10387     POINT pt;
10388     DWORD_PTR res;
10389     CPINFOEXA cpinfo;
10390     UINT i, j, k;
10391     struct message wmCharSeq[2];
10392
10393     if (!pGetCPInfoExA)
10394     {
10395         skip("GetCPInfoExA is not available\n");
10396         return;
10397     }
10398
10399     pGetCPInfoExA( CP_ACP, 0, &cpinfo );
10400     if (cpinfo.MaxCharSize != 2)
10401     {
10402         skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
10403         return;
10404     }
10405
10406     dbch[0] = dbch[1] = 0;
10407     wch = 0;
10408     bad_wch = cpinfo.UnicodeDefaultChar;
10409     for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
10410         for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
10411             for (k = 128; k <= 255; k++)
10412             {
10413                 char str[2];
10414                 WCHAR wstr[2];
10415                 str[0] = j;
10416                 str[1] = k;
10417                 if (MultiByteToWideChar( CP_ACP, 0, str, 2, wstr, 2 ) == 1 &&
10418                     WideCharToMultiByte( CP_ACP, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
10419                     (BYTE)str[0] == j && (BYTE)str[1] == k &&
10420                     HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
10421                 {
10422                     dbch[0] = j;
10423                     dbch[1] = k;
10424                     wch = wstr[0];
10425                     break;
10426                 }
10427             }
10428
10429     if (!wch)
10430     {
10431         skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
10432         return;
10433     }
10434     trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
10435            dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
10436
10437     hwnd = CreateWindowExW(0, testWindowClassW, NULL,
10438                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
10439     hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
10440                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
10441     ok (hwnd != 0, "Failed to create overlapped window\n");
10442     ok (hwnd2 != 0, "Failed to create overlapped window\n");
10443     flush_sequence();
10444
10445     memset( wmCharSeq, 0, sizeof(wmCharSeq) );
10446     wmCharSeq[0].message = WM_CHAR;
10447     wmCharSeq[0].flags = sent|wparam;
10448     wmCharSeq[0].wParam = wch;
10449
10450     /* posted message */
10451     PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10452     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10453     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10454     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10455     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10456     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
10457     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10458
10459     /* posted thread message */
10460     PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
10461     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10462     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10463     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10464     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10465     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
10466     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10467
10468     /* sent message */
10469     flush_sequence();
10470     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10471     ok_sequence( WmEmptySeq, "no messages", FALSE );
10472     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10473     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10474     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10475
10476     /* sent message with timeout */
10477     flush_sequence();
10478     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
10479     ok_sequence( WmEmptySeq, "no messages", FALSE );
10480     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
10481     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10482     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10483
10484     /* sent message with timeout and callback */
10485     flush_sequence();
10486     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
10487     ok_sequence( WmEmptySeq, "no messages", FALSE );
10488     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
10489     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10490     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10491
10492     /* sent message with callback */
10493     flush_sequence();
10494     SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10495     ok_sequence( WmEmptySeq, "no messages", FALSE );
10496     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
10497     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10498     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10499
10500     /* direct window proc call */
10501     flush_sequence();
10502     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
10503     ok_sequence( WmEmptySeq, "no messages", FALSE );
10504     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
10505     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10506
10507     /* dispatch message */
10508     msg.hwnd = hwnd;
10509     msg.message = WM_CHAR;
10510     msg.wParam = dbch[0];
10511     msg.lParam = 0;
10512     DispatchMessageA( &msg );
10513     ok_sequence( WmEmptySeq, "no messages", FALSE );
10514     msg.wParam = dbch[1];
10515     DispatchMessageA( &msg );
10516     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10517
10518     /* window handle is irrelevant */
10519     flush_sequence();
10520     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
10521     ok_sequence( WmEmptySeq, "no messages", FALSE );
10522     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10523     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10524     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10525
10526     /* interleaved post and send */
10527     flush_sequence();
10528     PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
10529     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
10530     ok_sequence( WmEmptySeq, "no messages", FALSE );
10531     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10532     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10533     ok_sequence( WmEmptySeq, "no messages", FALSE );
10534     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10535     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10536     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
10537     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10538     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10539     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10540     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10541
10542     /* interleaved sent message and winproc */
10543     flush_sequence();
10544     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10545     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
10546     ok_sequence( WmEmptySeq, "no messages", FALSE );
10547     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10548     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10549     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
10550     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10551
10552     /* interleaved winproc and dispatch */
10553     msg.hwnd = hwnd;
10554     msg.message = WM_CHAR;
10555     msg.wParam = dbch[0];
10556     msg.lParam = 0;
10557     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
10558     DispatchMessageA( &msg );
10559     ok_sequence( WmEmptySeq, "no messages", FALSE );
10560     msg.wParam = dbch[1];
10561     DispatchMessageA( &msg );
10562     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10563     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
10564     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10565
10566     /* interleaved sends */
10567     flush_sequence();
10568     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10569     SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
10570     ok_sequence( WmEmptySeq, "no messages", FALSE );
10571     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
10572     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10573     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10574     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10575
10576     /* dbcs WM_CHAR */
10577     flush_sequence();
10578     SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
10579     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10580     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10581
10582     /* other char messages are not magic */
10583     PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
10584     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10585     ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
10586     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
10587     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10588     PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
10589     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10590     ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
10591     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
10592     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10593
10594     /* test retrieving messages */
10595
10596     PostMessageW( hwnd, WM_CHAR, wch, 0 );
10597     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10598     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10599     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10600     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10601     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10602     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10603     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10604     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10605     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10606
10607     /* message filters */
10608     PostMessageW( hwnd, WM_CHAR, wch, 0 );
10609     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10610     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10611     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10612     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10613     /* message id is filtered, hwnd is not */
10614     ok( !PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ), "no message\n" );
10615     ok( PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE ), "no message\n" );
10616     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10617     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10618     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10619     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10620
10621     /* mixing GetMessage and PostMessage */
10622     PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
10623     ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
10624     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10625     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10626     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10627     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
10628     time = msg.time;
10629     pt = msg.pt;
10630     ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time );
10631     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
10632     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10633     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10634     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10635     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
10636     ok( msg.time == time, "bad time %x/%x\n", msg.time, time );
10637     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 );
10638     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10639
10640     /* without PM_REMOVE */
10641     PostMessageW( hwnd, WM_CHAR, wch, 0 );
10642     ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
10643     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10644     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10645     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10646     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
10647     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10648     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10649     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10650     ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
10651     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10652     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10653     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10654     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
10655     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10656     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10657     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10658     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10659
10660     DestroyWindow(hwnd);
10661 }
10662
10663 #define ID_LISTBOX 0x000f
10664
10665 static const struct message wm_lb_setcursel_0[] =
10666 {
10667     { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
10668     { WM_CTLCOLORLISTBOX, sent|parent },
10669     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
10670     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
10671     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
10672     { 0 }
10673 };
10674 static const struct message wm_lb_setcursel_1[] =
10675 {
10676     { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
10677     { WM_CTLCOLORLISTBOX, sent|parent },
10678     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
10679     { WM_CTLCOLORLISTBOX, sent|parent },
10680     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
10681     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
10682     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
10683     { 0 }
10684 };
10685 static const struct message wm_lb_setcursel_2[] =
10686 {
10687     { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
10688     { WM_CTLCOLORLISTBOX, sent|parent },
10689     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
10690     { WM_CTLCOLORLISTBOX, sent|parent },
10691     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
10692     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
10693     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
10694     { 0 }
10695 };
10696 static const struct message wm_lb_click_0[] =
10697 {
10698     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
10699     { HCBT_SETFOCUS, hook },
10700     { WM_KILLFOCUS, sent|parent },
10701     { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
10702     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10703     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10704     { WM_SETFOCUS, sent|defwinproc },
10705
10706     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
10707     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
10708     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
10709     { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
10710     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
10711
10712     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
10713     { WM_CTLCOLORLISTBOX, sent|parent },
10714     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
10715     { WM_CTLCOLORLISTBOX, sent|parent },
10716     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
10717     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
10718
10719     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
10720     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
10721
10722     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
10723     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
10724     { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
10725     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
10726     { 0 }
10727 };
10728
10729 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
10730
10731 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
10732
10733 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
10734 {
10735     static long defwndproc_counter = 0;
10736     LRESULT ret;
10737     struct message msg;
10738
10739     /* do not log painting messages */
10740     if (message != WM_PAINT &&
10741         message != WM_NCPAINT &&
10742         message != WM_SYNCPAINT &&
10743         message != WM_ERASEBKGND &&
10744         message != WM_NCHITTEST &&
10745         message != WM_GETTEXT &&
10746         message != WM_GETICON &&
10747         message != WM_DEVICECHANGE)
10748     {
10749         trace("listbox: %p, %04x, %08lx, %08lx\n", hwnd, message, wp, lp);
10750
10751         msg.message = message;
10752         msg.flags = sent|wparam|lparam;
10753         if (defwndproc_counter) msg.flags |= defwinproc;
10754         msg.wParam = wp;
10755         msg.lParam = lp;
10756         add_message(&msg);
10757     }
10758
10759     defwndproc_counter++;
10760     ret = CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
10761     defwndproc_counter--;
10762
10763     return ret;
10764 }
10765
10766 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
10767                                int caret_index, int top_index, int line)
10768 {
10769     LRESULT ret;
10770
10771     /* calling an orig proc helps to avoid unnecessary message logging */
10772     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
10773     ok_(__FILE__, line)(ret == count, "expected count %d, got %ld\n", count, ret);
10774     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
10775     ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret);
10776     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
10777     ok_(__FILE__, line)(ret == caret_index, "expected caret index %d, got %ld\n", caret_index, ret);
10778     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
10779     ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret);
10780 }
10781
10782 static void test_listbox_messages(void)
10783 {
10784     HWND parent, listbox;
10785     LRESULT ret;
10786
10787     parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW  | WS_VISIBLE,
10788                              100, 100, 200, 200, 0, 0, 0, NULL);
10789     listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
10790                               WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
10791                               10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
10792     listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
10793
10794     check_lb_state(listbox, 0, LB_ERR, 0, 0);
10795
10796     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
10797     ok(ret == 0, "expected 0, got %ld\n", ret);
10798     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
10799     ok(ret == 1, "expected 1, got %ld\n", ret);
10800     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
10801     ok(ret == 2, "expected 2, got %ld\n", ret);
10802
10803     check_lb_state(listbox, 3, LB_ERR, 0, 0);
10804
10805     flush_sequence();
10806
10807     log_all_parent_messages++;
10808
10809     trace("selecting item 0\n");
10810     ret = SendMessage(listbox, LB_SETCURSEL, 0, 0);
10811     ok(ret == 0, "expected 0, got %ld\n", ret);
10812     ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
10813     check_lb_state(listbox, 3, 0, 0, 0);
10814     flush_sequence();
10815
10816     trace("selecting item 1\n");
10817     ret = SendMessage(listbox, LB_SETCURSEL, 1, 0);
10818     ok(ret == 1, "expected 1, got %ld\n", ret);
10819     ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
10820     check_lb_state(listbox, 3, 1, 1, 0);
10821
10822     trace("selecting item 2\n");
10823     ret = SendMessage(listbox, LB_SETCURSEL, 2, 0);
10824     ok(ret == 2, "expected 2, got %ld\n", ret);
10825     ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
10826     check_lb_state(listbox, 3, 2, 2, 0);
10827
10828     trace("clicking on item 0\n");
10829     ret = SendMessage(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
10830     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
10831     ret = SendMessage(listbox, WM_LBUTTONUP, 0, 0);
10832     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
10833     ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
10834     check_lb_state(listbox, 3, 0, 0, 0);
10835     flush_sequence();
10836
10837     log_all_parent_messages--;
10838
10839     DestroyWindow(listbox);
10840     DestroyWindow(parent);
10841 }
10842
10843 /*************************** Menu test ******************************/
10844 static const struct message wm_popup_menu_1[] =
10845 {
10846     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
10847     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
10848     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0x20000001 },
10849     { WM_SYSKEYDOWN, sent|wparam|lparam, 'E', 0x20000001 },
10850     { WM_SYSCHAR, sent|wparam|lparam, 'e', 0x20000001 },
10851     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'e' },
10852     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
10853     { WM_INITMENU, sent|lparam, 0, 0 },
10854     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) },
10855     { WM_INITMENUPOPUP, sent|lparam, 0, 1 },
10856     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */
10857     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) },
10858     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 },
10859     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
10860     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
10861     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */
10862     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
10863     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
10864     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
10865     { WM_MENUCOMMAND, sent }, /* |wparam, 200 - Win9x */
10866     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
10867     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
10868     { 0 }
10869 };
10870 static const struct message wm_popup_menu_2[] =
10871 {
10872     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
10873     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
10874     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
10875     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
10876     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
10877     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
10878     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
10879     { WM_INITMENU, sent|lparam, 0, 0 },
10880     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
10881     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
10882     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
10883     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
10884     { HCBT_CREATEWND, hook },
10885     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
10886                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
10887     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
10888     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
10889     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
10890     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
10891     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
10892     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
10893     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
10894     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
10895     { HCBT_DESTROYWND, hook },
10896     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
10897     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
10898     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
10899     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
10900     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
10901     { WM_MENUCOMMAND, sent }, /* |wparam, 100 - Win9x */
10902     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
10903     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
10904     { 0 }
10905 };
10906 static const struct message wm_popup_menu_3[] =
10907 {
10908     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
10909     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
10910     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
10911     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
10912     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
10913     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
10914     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
10915     { WM_INITMENU, sent|lparam, 0, 0 },
10916     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
10917     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
10918     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
10919     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
10920     { HCBT_CREATEWND, hook },
10921     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
10922                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
10923     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
10924     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
10925     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
10926     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
10927     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
10928     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
10929     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
10930     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
10931     { HCBT_DESTROYWND, hook },
10932     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
10933     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
10934     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
10935     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
10936     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
10937     { WM_COMMAND, sent|wparam|lparam, 100, 0 },
10938     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
10939     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
10940     { 0 }
10941 };
10942
10943 static LRESULT WINAPI parent_menu_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
10944 {
10945     if (message == WM_ENTERIDLE ||
10946         message == WM_INITMENU ||
10947         message == WM_INITMENUPOPUP ||
10948         message == WM_MENUSELECT ||
10949         message == WM_PARENTNOTIFY ||
10950         message == WM_ENTERMENULOOP ||
10951         message == WM_EXITMENULOOP ||
10952         message == WM_UNINITMENUPOPUP ||
10953         message == WM_KEYDOWN ||
10954         message == WM_KEYUP ||
10955         message == WM_CHAR ||
10956         message == WM_SYSKEYDOWN ||
10957         message == WM_SYSKEYUP ||
10958         message == WM_SYSCHAR ||
10959         message == WM_COMMAND ||
10960         message == WM_MENUCOMMAND)
10961     {
10962         struct message msg;
10963
10964         trace("parent_menu_proc: %p, %04x, %08lx, %08lx\n", hwnd, message, wp, lp);
10965
10966         msg.message = message;
10967         msg.flags = sent|wparam|lparam;
10968         msg.wParam = wp;
10969         msg.lParam = lp;
10970         add_message(&msg);
10971     }
10972
10973     return DefWindowProcA(hwnd, message, wp, lp);
10974 }
10975
10976 static void set_menu_style(HMENU hmenu, DWORD style)
10977 {
10978     MENUINFO mi;
10979     BOOL ret;
10980
10981     mi.cbSize = sizeof(mi);
10982     mi.fMask = MIM_STYLE;
10983     mi.dwStyle = style;
10984     SetLastError(0xdeadbeef);
10985     ret = pSetMenuInfo(hmenu, &mi);
10986     ok(ret, "SetMenuInfo error %u\n", GetLastError());
10987 }
10988
10989 static DWORD get_menu_style(HMENU hmenu)
10990 {
10991     MENUINFO mi;
10992     BOOL ret;
10993
10994     mi.cbSize = sizeof(mi);
10995     mi.fMask = MIM_STYLE;
10996     mi.dwStyle = 0;
10997     SetLastError(0xdeadbeef);
10998     ret = pGetMenuInfo(hmenu, &mi);
10999     ok(ret, "GetMenuInfo error %u\n", GetLastError());
11000
11001     return mi.dwStyle;
11002 }
11003
11004 static void test_menu_messages(void)
11005 {
11006     MSG msg;
11007     WNDCLASSA cls;
11008     HMENU hmenu, hmenu_popup;
11009     HWND hwnd;
11010     DWORD style;
11011
11012     if (!pGetMenuInfo || !pSetMenuInfo)
11013     {
11014         skip("GetMenuInfo and/or SetMenuInfo are not available\n");
11015         return;
11016     }
11017     cls.style = 0;
11018     cls.lpfnWndProc = parent_menu_proc;
11019     cls.cbClsExtra = 0;
11020     cls.cbWndExtra = 0;
11021     cls.hInstance = GetModuleHandleA(0);
11022     cls.hIcon = 0;
11023     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
11024     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
11025     cls.lpszMenuName = NULL;
11026     cls.lpszClassName = "TestMenuClass";
11027     UnregisterClass(cls.lpszClassName, cls.hInstance);
11028     if (!RegisterClassA(&cls)) assert(0);
11029
11030     SetLastError(0xdeadbeef);
11031     hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11032                            100, 100, 200, 200, 0, 0, 0, NULL);
11033     ok(hwnd != 0, "LoadMenuA error %u\n", GetLastError());
11034
11035     SetLastError(0xdeadbeef);
11036     hmenu = LoadMenuA(GetModuleHandle(0), MAKEINTRESOURCE(1));
11037     ok(hmenu != 0, "LoadMenuA error %u\n", GetLastError());
11038
11039     SetMenu(hwnd, hmenu);
11040     SetForegroundWindow( hwnd );
11041
11042     set_menu_style(hmenu, MNS_NOTIFYBYPOS);
11043     style = get_menu_style(hmenu);
11044     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
11045
11046     hmenu_popup = GetSubMenu(hmenu, 0);
11047     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11048     style = get_menu_style(hmenu_popup);
11049     ok(style == 0, "expected 0, got %u\n", style);
11050
11051     hmenu_popup = GetSubMenu(hmenu_popup, 0);
11052     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11053     style = get_menu_style(hmenu_popup);
11054     ok(style == 0, "expected 0, got %u\n", style);
11055
11056     /* Alt+E, Enter */
11057     trace("testing a popup menu command\n");
11058     flush_sequence();
11059     keybd_event(VK_MENU, 0, 0, 0);
11060     keybd_event('E', 0, 0, 0);
11061     keybd_event('E', 0, KEYEVENTF_KEYUP, 0);
11062     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
11063     keybd_event(VK_RETURN, 0, 0, 0);
11064     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
11065     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
11066     {
11067         TranslateMessage(&msg);
11068         DispatchMessage(&msg);
11069     }
11070     ok_sequence(wm_popup_menu_1, "popup menu command", FALSE);
11071
11072     /* Alt+F, Right, Enter */
11073     trace("testing submenu of a popup menu command\n");
11074     flush_sequence();
11075     keybd_event(VK_MENU, 0, 0, 0);
11076     keybd_event('F', 0, 0, 0);
11077     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
11078     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
11079     keybd_event(VK_RIGHT, 0, 0, 0);
11080     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
11081     keybd_event(VK_RETURN, 0, 0, 0);
11082     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
11083     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
11084     {
11085         TranslateMessage(&msg);
11086         DispatchMessage(&msg);
11087     }
11088     ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE);
11089
11090     set_menu_style(hmenu, 0);
11091     style = get_menu_style(hmenu);
11092     ok(style == 0, "expected 0, got %u\n", style);
11093
11094     hmenu_popup = GetSubMenu(hmenu, 0);
11095     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11096     set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS);
11097     style = get_menu_style(hmenu_popup);
11098     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
11099
11100     hmenu_popup = GetSubMenu(hmenu_popup, 0);
11101     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11102     style = get_menu_style(hmenu_popup);
11103     ok(style == 0, "expected 0, got %u\n", style);
11104
11105     /* Alt+F, Right, Enter */
11106     trace("testing submenu of a popup menu command\n");
11107     flush_sequence();
11108     keybd_event(VK_MENU, 0, 0, 0);
11109     keybd_event('F', 0, 0, 0);
11110     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
11111     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
11112     keybd_event(VK_RIGHT, 0, 0, 0);
11113     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
11114     keybd_event(VK_RETURN, 0, 0, 0);
11115     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
11116     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
11117     {
11118         TranslateMessage(&msg);
11119         DispatchMessage(&msg);
11120     }
11121     ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE);
11122
11123     DestroyWindow(hwnd);
11124     DestroyMenu(hmenu);
11125 }
11126
11127
11128 static void test_paintingloop(void)
11129 {
11130     HWND hwnd;
11131
11132     paint_loop_done = 0;
11133     hwnd = CreateWindowExA(0x0,"PaintLoopWindowClass",
11134                                "PaintLoopWindowClass",WS_OVERLAPPEDWINDOW,
11135                                 100, 100, 100, 100, 0, 0, 0, NULL );
11136     ok(hwnd != 0, "PaintLoop window error %u\n", GetLastError());
11137     ShowWindow(hwnd,SW_NORMAL);
11138     SetFocus(hwnd);
11139
11140     while (!paint_loop_done)
11141     {
11142         MSG msg;
11143         if (PeekMessageA(&msg, 0, 0, 0, 1))
11144         {
11145             TranslateMessage(&msg);
11146             DispatchMessage(&msg);
11147         }
11148     }
11149     DestroyWindow(hwnd);
11150 }
11151
11152 START_TEST(msg)
11153 {
11154     BOOL ret;
11155     FARPROC pIsWinEventHookInstalled = 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
11156
11157     init_procs();
11158
11159     if (!RegisterWindowClasses()) assert(0);
11160
11161     if (pSetWinEventHook)
11162     {
11163         hEvent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
11164                                                       GetModuleHandleA(0),
11165                                                       win_event_proc,
11166                                                       0,
11167                                                       GetCurrentThreadId(),
11168                                                       WINEVENT_INCONTEXT);
11169         assert(hEvent_hook);
11170
11171         if (pIsWinEventHookInstalled)
11172         {
11173             UINT event;
11174             for (event = EVENT_MIN; event <= EVENT_MAX; event++)
11175                 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
11176         }
11177     }
11178
11179     cbt_hook_thread_id = GetCurrentThreadId();
11180     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
11181     assert(hCBT_hook);
11182
11183     test_winevents();
11184
11185     /* Fix message sequences before removing 4 lines below */
11186 #if 1
11187     if (pUnhookWinEvent && hEvent_hook)
11188     {
11189         ret = pUnhookWinEvent(hEvent_hook);
11190         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
11191         pUnhookWinEvent = 0;
11192     }
11193     hEvent_hook = 0;
11194 #endif
11195
11196     test_ShowWindow();
11197     test_PeekMessage();
11198     test_PeekMessage2();
11199     test_scrollwindowex();
11200     test_messages();
11201     test_setwindowpos();
11202     test_showwindow();
11203     invisible_parent_tests();
11204     test_mdi_messages();
11205     test_button_messages();
11206     test_static_messages();
11207     test_listbox_messages();
11208     test_combobox_messages();
11209     test_wmime_keydown_message();
11210     test_paint_messages();
11211     test_interthread_messages();
11212     test_message_conversion();
11213     test_accelerators();
11214     test_timers();
11215     test_timers_no_wnd();
11216     test_set_hook();
11217     test_DestroyWindow();
11218     test_DispatchMessage();
11219     test_SendMessageTimeout();
11220     test_edit_messages();
11221     test_quit_message();
11222     test_SetActiveWindow();
11223
11224     if (!pTrackMouseEvent)
11225         skip("TrackMouseEvent is not available\n");
11226     else
11227         test_TrackMouseEvent();
11228
11229     test_SetWindowRgn();
11230     test_sys_menu();
11231     test_dialog_messages();
11232     test_nullCallback();
11233     test_dbcs_wm_char();
11234     test_menu_messages();
11235     test_paintingloop();
11236     /* keep it the last test, under Windows it tends to break the tests
11237      * which rely on active/foreground windows being correct.
11238      */
11239     test_SetForegroundWindow();
11240
11241     UnhookWindowsHookEx(hCBT_hook);
11242     if (pUnhookWinEvent)
11243     {
11244         ret = pUnhookWinEvent(hEvent_hook);
11245         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
11246         SetLastError(0xdeadbeef);
11247         ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
11248         ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
11249            GetLastError() == 0xdeadbeef, /* Win9x */
11250            "unexpected error %d\n", GetLastError());
11251     }
11252     else
11253         skip("UnhookWinEvent is not available\n");
11254 }