1 /*
2  * Unit tests for window message handling
3  *
4  * Copyright 1999 Ove Kaaven
5  * Copyright 2003 Dimitrie O. Paun
6  * Copyright 2004,2005,2016 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 <limits.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "winuser.h"
32 #include "winnls.h"
33 #include "dbt.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 #ifdef __i386__
63 #define ARCH "x86"
64 #elif defined __x86_64__
65 #define ARCH "amd64"
66 #elif defined __arm__
67 #define ARCH "arm"
68 #elif defined __aarch64__
69 #define ARCH "arm64"
70 #else
71 #define ARCH "none"
72 #endif
73 
74 static BOOL   (WINAPI *pActivateActCtx)(HANDLE,ULONG_PTR*);
75 static HANDLE (WINAPI *pCreateActCtxW)(PCACTCTXW);
76 static BOOL   (WINAPI *pDeactivateActCtx)(DWORD,ULONG_PTR);
77 static BOOL   (WINAPI *pGetCurrentActCtx)(HANDLE *);
78 static BOOL   (WINAPI *pQueryActCtxW)(DWORD,HANDLE,void*,ULONG,void*,SIZE_T,SIZE_T*);
79 static void   (WINAPI *pReleaseActCtx)(HANDLE);
80 
81 /* encoded DRAWITEMSTRUCT into an LPARAM */
82 typedef struct
83 {
84     union
85     {
86         struct
87         {
88             UINT type    : 4;  /* ODT_* flags */
89             UINT ctl_id  : 4;  /* Control ID */
90             UINT item_id : 4;  /* Menu item ID */
91             UINT action  : 4;  /* ODA_* flags */
92             UINT state   : 16; /* ODS_* flags */
93         } item;
94         LPARAM lp;
95     } u;
96 } DRAW_ITEM_STRUCT;
97 
98 /* encoded MEASUREITEMSTRUCT into a WPARAM */
99 typedef struct
100 {
101     union
102     {
103         struct
104         {
105             UINT CtlType : 4;
106             UINT CtlID   : 4;
107             UINT itemID  : 4;
108             UINT wParam  : 20;
109         } item;
110         WPARAM wp;
111     } u;
112 } MEASURE_ITEM_STRUCT;
113 
114 static BOOL test_DestroyWindow_flag;
115 static HWINEVENTHOOK hEvent_hook;
116 static HHOOK hKBD_hook;
117 static HHOOK hCBT_hook;
118 static DWORD cbt_hook_thread_id;
119 
120 static const WCHAR testWindowClassW[] =
121 { 'T','e','s','t','W','i','n','d','o','w','C','l','a','s','s','W',0 };
122 
123 static LRESULT WINAPI ParentMsgCheckProcA(HWND, UINT, WPARAM, LPARAM);
124 
125 /*
126 FIXME: add tests for these
127 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
128  WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
129  WS_THICKFRAME: thick border
130  WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
131  WS_BORDER (default for overlapped windows): single black border
132  none (default for child (and popup?) windows): no border
133 */
134 
135 typedef enum {
136     sent=0x1,
137     posted=0x2,
138     parent=0x4,
139     wparam=0x8,
140     lparam=0x10,
141     defwinproc=0x20,
142     beginpaint=0x40,
143     optional=0x80,
144     hook=0x100,
145     winevent_hook=0x200,
146     kbd_hook=0x400
147 } msg_flags_t;
148 
149 struct message {
150     UINT message;          /* the WM_* code */
151     msg_flags_t flags;     /* message props */
152     WPARAM wParam;         /* expected value of wParam */
153     LPARAM lParam;         /* expected value of lParam */
154     WPARAM wp_mask;        /* mask for wParam checks */
155     LPARAM lp_mask;        /* mask for lParam checks */
156 };
157 
158 struct recvd_message {
159     UINT message;          /* the WM_* code */
160     msg_flags_t flags;     /* message props */
161     HWND hwnd;             /* window that received the message */
162     WPARAM wParam;         /* expected value of wParam */
163     LPARAM lParam;         /* expected value of lParam */
164     int line;              /* source line where logged */
165     const char *descr;     /* description for trace output */
166     char output[512];      /* trace output */
167 };
168 
169 /* Empty message sequence */
170 static const struct message WmEmptySeq[] =
171 {
172     { 0 }
173 };
174 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
175 static const struct message WmCreateOverlappedSeq[] = {
176     { HCBT_CREATEWND, hook },
177     { WM_GETMINMAXINFO, sent },
178     { WM_NCCREATE, sent },
179     { WM_NCCALCSIZE, sent|wparam, 0 },
180     { 0x0093, sent|defwinproc|optional },
181     { 0x0094, sent|defwinproc|optional },
182     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
183     { WM_CREATE, sent },
184     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
185     { 0 }
186 };
187 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
188  * for a not visible overlapped window.
189  */
190 static const struct message WmSWP_ShowOverlappedSeq[] = {
191     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
192     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
193     { WM_NCPAINT, sent|wparam|optional, 1 },
194     { WM_GETTEXT, sent|defwinproc|optional },
195     { WM_ERASEBKGND, sent|optional },
196     { HCBT_ACTIVATE, hook },
197     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
198     { WM_NOTIFYFORMAT, sent|optional },
199     { WM_QUERYUISTATE, sent|optional },
200     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
201     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
202     { WM_ACTIVATEAPP, sent|wparam, 1 },
203     { WM_NCACTIVATE, sent },
204     { WM_GETTEXT, sent|defwinproc|optional },
205     { WM_ACTIVATE, sent|wparam, 1 },
206     { HCBT_SETFOCUS, hook },
207     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
208     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
209     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
210     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
211     { WM_GETTEXT, sent|optional },
212     { WM_NCPAINT, sent|wparam|optional, 1 },
213     { WM_GETTEXT, sent|defwinproc|optional },
214     { WM_ERASEBKGND, sent|optional },
215     /* Win9x adds SWP_NOZORDER below */
216     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
217     { WM_GETTEXT, sent|optional },
218     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
219     { WM_NCPAINT, sent|wparam|optional, 1 },
220     { WM_ERASEBKGND, sent|optional },
221     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
222     { WM_SYNCPAINT, sent|optional },
223     { WM_GETTITLEBARINFOEX, sent|optional },
224     { WM_PAINT, sent|optional },
225     { WM_NCPAINT, sent|beginpaint|optional },
226     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
227     { WM_ERASEBKGND, sent|beginpaint|optional },
228     { 0 }
229 };
230 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
231  * for a visible overlapped window.
232  */
233 static const struct message WmSWP_HideOverlappedSeq[] = {
234     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
235     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
236     { HCBT_ACTIVATE, hook|optional },
237     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
238     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
239     { WM_NCACTIVATE, sent|optional },
240     { WM_ACTIVATE, sent|optional },
241     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
242     { 0 }
243 };
244 
245 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
246  * for a visible overlapped window.
247  */
248 static const struct message WmSWP_ResizeSeq[] = {
249     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
250     { WM_GETMINMAXINFO, sent|defwinproc },
251     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
252     { WM_NCPAINT, sent|optional },
253     { WM_GETTEXT, sent|defwinproc|optional },
254     { WM_ERASEBKGND, sent|optional },
255     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
256     { WM_SIZE, sent|defwinproc|optional },
257     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
258     { WM_NCPAINT, sent|optional },
259     { WM_GETTEXT, sent|defwinproc|optional },
260     { WM_ERASEBKGND, sent|optional },
261     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
262     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
263     { 0 }
264 };
265 
266 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
267  * for a visible popup window.
268  */
269 static const struct message WmSWP_ResizePopupSeq[] = {
270     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
271     { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* Win9x */
272     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
273     { WM_NCPAINT, sent|optional },
274     { WM_GETTEXT, sent|defwinproc|optional },
275     { WM_ERASEBKGND, sent|optional },
276     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
277     { WM_SIZE, sent|defwinproc|wparam|optional, SIZE_RESTORED },
278     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
279     { WM_NCPAINT, sent|optional },
280     { WM_GETTEXT, sent|defwinproc|optional },
281     { WM_ERASEBKGND, sent|optional },
282     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
283     { 0 }
284 };
285 
286 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE)
287  * for a visible overlapped window.
288  */
289 static const struct message WmSWP_MoveSeq[] = {
290     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE },
291     { WM_NCPAINT, sent|optional },
292     { WM_GETTEXT, sent|defwinproc|optional },
293     { WM_ERASEBKGND, sent|optional },
294     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
295     { WM_MOVE, sent|defwinproc|wparam, 0 },
296     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
297     { 0 }
298 };
299 /* Resize with SetWindowPos(SWP_NOZORDER)
300  * for a visible overlapped window
301  * SWP_NOZORDER is stripped by the logging code
302  */
303 static const struct message WmSWP_ResizeNoZOrder[] = {
304     { WM_WINDOWPOSCHANGING, sent|wparam, /*SWP_NOZORDER|*/SWP_NOACTIVATE },
305     { WM_GETMINMAXINFO, sent|defwinproc },
306     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
307     { WM_NCPAINT, sent|optional },
308     { WM_GETTEXT, sent|defwinproc|optional },
309     { WM_ERASEBKGND, sent|optional },
310     { WM_WINDOWPOSCHANGED, sent|wparam|optional, /*SWP_NOZORDER|*/SWP_NOACTIVATE, 0,
311       SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
312     { WM_MOVE, sent|defwinproc|optional },
313     { WM_SIZE, sent|defwinproc|optional },
314     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
315     { WM_NCPAINT, sent|optional }, /* Win9x doesn't send it */
316     { WM_GETTEXT, sent|defwinproc|optional }, /* Win9x doesn't send it */
317     { WM_ERASEBKGND, sent|optional }, /* Win9x doesn't send it */
318     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
319     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
320     { 0 }
321 };
322 
323 /* Switch visible mdi children */
324 static const struct message WmSwitchChild[] = {
325     /* Switch MDI child */
326     { WM_MDIACTIVATE, sent },/* in the MDI client */
327     { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 1st MDI child */
328     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
329     { WM_CHILDACTIVATE, sent },/* in the 1st MDI child */
330     /* Deactivate 2nd MDI child */
331     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
332     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
333     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
334     /* Preparing for maximize and maximize the 1st MDI child */
335     { WM_GETMINMAXINFO, sent|defwinproc }, /* in the 1st MDI child */
336     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED }, /* in the 1st MDI child */
337     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
338     { WM_CHILDACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
339     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 1st MDI child */
340     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, /* in the 1st MDI child */
341     /* Lock redraw 2nd MDI child */
342     { WM_SETREDRAW, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
343     { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
344     /* Restore 2nd MDI child */
345     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },/* in the 2nd MDI child */
346     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
347     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
348     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 2nd MDI child */
349     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, /* in the 2nd MDI child */
350     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
351     /* Redraw 2nd MDI child */
352     { WM_SETREDRAW, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
353     /* Redraw MDI frame */
354     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },/* in MDI frame */
355     { WM_NCCALCSIZE, sent|wparam, 1 },/* in MDI frame */
356     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in MDI frame */
357     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in MDI frame */
358     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
359     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
360     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
361     { HCBT_SETFOCUS, hook },
362     { WM_KILLFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
363     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },/* in the 1st MDI child */
364     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
365     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
366     { WM_SETFOCUS, sent },/* in the MDI client */
367     { HCBT_SETFOCUS, hook },
368     { WM_KILLFOCUS, sent },/* in the MDI client */
369     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
370     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, /* in the 1st MDI child */
371     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
372     { WM_SETFOCUS, sent|defwinproc }, /* in the 1st MDI child */
373     { WM_MDIACTIVATE, sent|defwinproc },/* in the 1st MDI child */
374     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* in the 1st MDI child */
375     { 0 }
376 };
377 
378 /* Switch visible not maximized mdi children */
379 static const struct message WmSwitchNotMaximizedChild[] = {
380     /* Switch not maximized MDI child */
381     { WM_MDIACTIVATE, sent },/* in the MDI client */
382     { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 2nd MDI child */
383     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
384     { WM_CHILDACTIVATE, sent },/* in the 2nd MDI child */
385     /* Deactivate 1st MDI child */
386     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
387     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
388     /* Activate 2nd MDI child */
389     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE}, /* in the 2nd MDI child */
390     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 2nd MDI child */
391     { HCBT_SETFOCUS, hook }, /* in the 1st MDI child */
392     { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
393     { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
394     { WM_IME_SETCONTEXT, sent|optional }, /* in the  MDI client */
395     { WM_SETFOCUS, sent, 0 }, /* in the  MDI client */
396     { HCBT_SETFOCUS, hook },
397     { WM_KILLFOCUS, sent }, /* in the  MDI client */
398     { WM_IME_SETCONTEXT, sent|optional }, /* in the  MDI client */
399     { WM_IME_SETCONTEXT, sent|defwinproc|optional  }, /* in the 1st MDI child */
400     { WM_SETFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
401     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
402     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in the 2nd MDI child */
403     { 0 }
404 };
405 
406 
407 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
408                 SWP_NOZORDER|SWP_FRAMECHANGED)
409  * for a visible overlapped window with WS_CLIPCHILDREN style set.
410  */
411 static const struct message WmSWP_FrameChanged_clip[] = {
412     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
413     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
414     { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
415     { WM_GETTEXT, sent|parent|defwinproc|optional },
416     { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
417     { WM_NCPAINT, sent }, /* wparam != 1 */
418     { WM_ERASEBKGND, sent },
419     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
420     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
421     { WM_PAINT, sent },
422     { 0 }
423 };
424 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|
425                 SWP_NOZORDER|SWP_FRAMECHANGED)
426  * for a visible overlapped window.
427  */
428 static const struct message WmSWP_FrameChangedDeferErase[] = {
429     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
430     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
431     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
432     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
433     { WM_PAINT, sent|parent|optional },
434     { WM_NCPAINT, sent|beginpaint|parent|optional }, /* wparam != 1 */
435     { WM_GETTEXT, sent|beginpaint|parent|defwinproc|optional },
436     { WM_PAINT, sent },
437     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
438     { WM_ERASEBKGND, sent|beginpaint|optional },
439     { 0 }
440 };
441 
442 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
443                 SWP_NOZORDER|SWP_FRAMECHANGED)
444  * for a visible overlapped window without WS_CLIPCHILDREN style set.
445  */
446 static const struct message WmSWP_FrameChanged_noclip[] = {
447     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
448     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
449     { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
450     { WM_GETTEXT, sent|parent|defwinproc|optional },
451     { WM_ERASEBKGND, sent|parent|optional },
452     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
453     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
454     { WM_PAINT, sent },
455     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
456     { WM_ERASEBKGND, sent|beginpaint|optional },
457     { 0 }
458 };
459 
460 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
461 static const struct message WmShowOverlappedSeq[] = {
462     { WM_SHOWWINDOW, sent|wparam, 1 },
463     { WM_NCPAINT, sent|wparam|optional, 1 },
464     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
465     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
466     { WM_NCPAINT, sent|wparam|optional, 1 },
467     { WM_GETTEXT, sent|defwinproc|optional },
468     { WM_ERASEBKGND, sent|optional },
469     { HCBT_ACTIVATE, hook|optional },
470     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
471     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
472     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
473     { WM_NCPAINT, sent|wparam|optional, 1 },
474     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
475     { WM_NCACTIVATE, sent|wparam|optional, 1 },
476     { WM_GETTEXT, sent|defwinproc|optional },
477     { WM_ACTIVATE, sent|wparam|optional, 1 },
478     { HCBT_SETFOCUS, hook|optional },
479     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
480     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
481     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
482     { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
483     { WM_GETTEXT, sent|optional },
484     { WM_NCPAINT, sent|wparam|optional, 1 },
485     { WM_GETTEXT, sent|defwinproc|optional },
486     { WM_ERASEBKGND, sent|optional },
487     /* Win9x adds SWP_NOZORDER below */
488     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
489     { WM_NCCALCSIZE, sent|optional },
490     { WM_GETTEXT, sent|optional },
491     { WM_NCPAINT, sent|optional },
492     { WM_ERASEBKGND, sent|optional },
493     { WM_SYNCPAINT, sent|optional },
494 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
495        * messages. Does that mean that CreateWindow doesn't set initial
496        * window dimensions for overlapped windows?
497        */
498     { WM_SIZE, sent },
499     { WM_MOVE, sent },
500 #endif
501     { WM_PAINT, sent|optional },
502     { WM_NCPAINT, sent|beginpaint|optional },
503     { 0 }
504 };
505 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible overlapped window */
506 static const struct message WmShowMaxOverlappedSeq[] = {
507     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
508     { WM_GETMINMAXINFO, sent },
509     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
510     { WM_GETMINMAXINFO, sent|defwinproc },
511     { WM_NCCALCSIZE, sent|wparam, TRUE },
512     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
513     { HCBT_ACTIVATE, hook|optional },
514     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
515     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
516     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
517     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
518     { WM_NCACTIVATE, sent|wparam|optional, 1 },
519     { WM_GETTEXT, sent|defwinproc|optional },
520     { WM_ACTIVATE, sent|wparam|optional, 1 },
521     { HCBT_SETFOCUS, hook|optional },
522     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
523     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
524     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
525     { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
526     { WM_GETTEXT, sent|optional },
527     { WM_NCPAINT, sent|wparam|optional, 1 },
528     { WM_GETTEXT, sent|defwinproc|optional },
529     { WM_ERASEBKGND, sent|optional },
530     /* Win9x adds SWP_NOZORDER below */
531     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
532     { WM_MOVE, sent|defwinproc },
533     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
534     { WM_GETTEXT, sent|optional },
535     { WM_NCCALCSIZE, sent|optional },
536     { WM_NCPAINT, sent|optional },
537     { WM_ERASEBKGND, sent|optional },
538     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
539     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
540     { WM_SYNCPAINT, sent|optional },
541     { WM_GETTITLEBARINFOEX, sent|optional },
542     { WM_PAINT, sent|optional },
543     { WM_NCPAINT, sent|beginpaint|optional },
544     { WM_ERASEBKGND, sent|beginpaint|optional },
545     { 0 }
546 };
547 /* ShowWindow(SW_RESTORE) for a not visible maximized overlapped window */
548 static const struct message WmShowRestoreMaxOverlappedSeq[] = {
549     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
550     { WM_GETTEXT, sent|optional },
551     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
552     { WM_GETMINMAXINFO, sent|defwinproc },
553     { WM_NCCALCSIZE, sent|wparam, TRUE },
554     { WM_NCPAINT, sent|optional },
555     { WM_GETTEXT, sent|defwinproc|optional },
556     { WM_ERASEBKGND, sent|optional },
557     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
558     { WM_MOVE, sent|defwinproc|optional },
559     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
560     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
561     { WM_NCPAINT, sent|optional },
562     { WM_ERASEBKGND, sent|optional },
563     { WM_PAINT, sent|optional },
564     { WM_GETTITLEBARINFOEX, sent|optional },
565     { WM_NCPAINT, sent|beginpaint|optional },
566     { WM_ERASEBKGND, sent|beginpaint|optional },
567     { WM_SYNCPAINT, sent|optional },
568     { 0 }
569 };
570 /* ShowWindow(SW_RESTORE) for a not visible minimized overlapped window */
571 static const struct message WmShowRestoreMinOverlappedSeq[] = {
572     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
573     { WM_QUERYOPEN, sent|optional },
574     { WM_GETTEXT, sent|optional },
575     { WM_NCACTIVATE, sent|wparam|optional, 1 },
576     { WM_WINDOWPOSCHANGING, sent|optional }, /* SWP_NOSIZE|SWP_NOMOVE */
577     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
578     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
579     { WM_MOVE, sent|optional },
580     { WM_SIZE, sent|wparam|optional, SIZE_RESTORED },
581     { WM_GETTEXT, sent|optional },
582     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED|SWP_NOCOPYBITS },
583     { WM_GETMINMAXINFO, sent|defwinproc|optional },
584     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
585     { HCBT_ACTIVATE, hook|optional },
586     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
587     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
588     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
589     { WM_NCACTIVATE, sent|wparam|optional, 1 },
590     { WM_GETTEXT, sent|defwinproc|optional },
591     { WM_ACTIVATE, sent|wparam|optional, 1 },
592     { HCBT_SETFOCUS, hook|optional },
593     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
594     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
595     { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
596     { WM_GETTEXT, sent|optional },
597     { WM_NCPAINT, sent|wparam|optional, 1 },
598     { WM_GETTEXT, sent|defwinproc|optional },
599     { WM_ERASEBKGND, sent },
600     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_STATECHANGED|SWP_FRAMECHANGED|SWP_NOCOPYBITS },
601     { WM_MOVE, sent|defwinproc },
602     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
603     { HCBT_SETFOCUS, hook|optional },
604     { WM_SETFOCUS, sent|wparam|optional, 0 },
605     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
606     { WM_NCPAINT, sent|wparam|optional, 1 },
607     { WM_ERASEBKGND, sent|optional },
608     { HCBT_SETFOCUS, hook|optional },
609     { WM_SETFOCUS, sent|wparam|optional, 0 },
610     { WM_ACTIVATE, sent|wparam, 1 },
611     { WM_GETTEXT, sent|optional },
612     { WM_PAINT, sent|optional },
613     { WM_GETTITLEBARINFOEX, sent|optional },
614     { WM_NCPAINT, sent|beginpaint|optional },
615     { WM_ERASEBKGND, sent|beginpaint|optional },
616     { 0 }
617 };
618 /* ShowWindow(SW_SHOWMINIMIZED) for a not visible overlapped window */
619 static const struct message WmShowMinOverlappedSeq[] = {
620     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
621     { HCBT_SETFOCUS, hook|optional },
622     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
623     { WM_KILLFOCUS, sent|optional },
624     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
625     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
626     { WM_GETTEXT, sent|optional },
627     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCOPYBITS|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
628     { WM_GETMINMAXINFO, sent|defwinproc },
629     { WM_NCCALCSIZE, sent|wparam, TRUE },
630     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
631     { WM_NCPAINT, sent|optional },
632     { WM_GETTEXT, sent|defwinproc|optional },
633     { WM_WINDOWPOSCHANGED, sent },
634     { WM_MOVE, sent|defwinproc },
635     { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
636     { WM_NCCALCSIZE, sent|optional },
637     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
638     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
639     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
640     { WM_NCACTIVATE, sent|wparam|optional, 0 },
641     { WM_GETTEXT, sent|defwinproc|optional },
642     { WM_ACTIVATE, sent|optional },
643     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
644 
645     /* Vista sometimes restores the window right away... */
646     { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
647     { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
648     { HCBT_MINMAX, hook|optional|lparam, 0, SW_RESTORE },
649     { WM_QUERYOPEN, sent|optional },
650     { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
651     { WM_GETMINMAXINFO, sent|optional|defwinproc },
652     { WM_NCCALCSIZE, sent|optional|wparam, TRUE },
653     { HCBT_ACTIVATE, hook|optional },
654     { WM_ACTIVATEAPP, sent|optional|wparam, 1 },
655     { WM_NCACTIVATE, sent|optional },
656     { WM_GETTEXT, sent|optional },
657     { WM_ACTIVATE, sent|optional|wparam, 1 },
658     { HCBT_SETFOCUS, hook|optional },
659     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
660     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
661     { WM_SETFOCUS, sent|optional },
662     { WM_NCPAINT, sent|optional },
663     { WM_GETTEXT, sent|defwinproc|optional },
664     { WM_ERASEBKGND, sent|optional },
665     { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
666     { WM_MOVE, sent|defwinproc|optional },
667     { WM_SIZE, sent|defwinproc|optional|wparam, SIZE_RESTORED },
668     { WM_ACTIVATE, sent|optional|wparam, 1 },
669     { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
670     { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
671 
672     { WM_PAINT, sent|optional },
673     { WM_NCPAINT, sent|beginpaint|optional },
674     { WM_ERASEBKGND, sent|beginpaint|optional },
675     { 0 }
676 };
677 /* ShowWindow(SW_HIDE) for a visible overlapped window */
678 static const struct message WmHideOverlappedSeq[] = {
679     { WM_SHOWWINDOW, sent|wparam, 0 },
680     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
681     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
682     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
683     { WM_SIZE, sent|optional }, /* XP doesn't send it */
684     { WM_MOVE, sent|optional }, /* XP doesn't send it */
685     { WM_NCACTIVATE, sent|wparam|optional, 0 },
686     { WM_ACTIVATE, sent|wparam|optional, 0 },
687     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
688     { HCBT_SETFOCUS, hook|optional },
689     { WM_KILLFOCUS, sent|wparam|optional, 0 },
690     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
691     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
692     { 0 }
693 };
694 /* DestroyWindow for a visible overlapped window */
695 static const struct message WmDestroyOverlappedSeq[] = {
696     { HCBT_DESTROYWND, hook },
697     { 0x0090, sent|optional },
698     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
699     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
700     { 0x0090, sent|optional },
701     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
702     { WM_NCACTIVATE, sent|optional|wparam, 0 },
703     { WM_ACTIVATE, sent|optional },
704     { WM_ACTIVATEAPP, sent|optional|wparam, 0 },
705     { WM_KILLFOCUS, sent|optional|wparam, 0 },
706     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
707     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
708     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
709     { WM_DESTROY, sent },
710     { WM_NCDESTROY, sent },
711     { 0 }
712 };
713 /* CreateWindow(WS_MAXIMIZE|WS_VISIBLE) for popup window */
714 static const struct message WmCreateMaxPopupSeq[] = {
715     { HCBT_CREATEWND, hook },
716     { WM_NCCREATE, sent },
717     { WM_NCCALCSIZE, sent|wparam, 0 },
718     { WM_CREATE, sent },
719     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
720     { WM_SIZE, sent|wparam, SIZE_RESTORED },
721     { WM_MOVE, sent },
722     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
723     { WM_GETMINMAXINFO, sent },
724     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
725     { WM_NCCALCSIZE, sent|wparam, TRUE },
726     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
727     { WM_MOVE, sent|defwinproc },
728     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
729     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
730     { WM_SHOWWINDOW, sent|wparam, 1 },
731     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
732     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
733     { HCBT_ACTIVATE, hook },
734     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
735     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
736     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
737     { WM_NCPAINT, sent|wparam|optional, 1 },
738     { WM_ERASEBKGND, sent|optional },
739     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_NOMOVE|SWP_NOSIZE },
740     { WM_ACTIVATEAPP, sent|wparam, 1 },
741     { WM_NCACTIVATE, sent },
742     { WM_ACTIVATE, sent|wparam, 1 },
743     { HCBT_SETFOCUS, hook },
744     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
745     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
746     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
747     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
748     { WM_GETTEXT, sent|optional },
749     { WM_SYNCPAINT, sent|wparam|optional, 4 },
750     { WM_NCPAINT, sent|wparam|optional, 1 },
751     { WM_ERASEBKGND, sent|optional },
752     { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
753     { WM_ERASEBKGND, sent|defwinproc|optional },
754     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
755     { 0 }
756 };
757 /* CreateWindow(WS_MAXIMIZE) for popup window, not initially visible */
758 static const struct message WmCreateInvisibleMaxPopupSeq[] = {
759     { HCBT_CREATEWND, hook },
760     { WM_NCCREATE, sent },
761     { WM_NCCALCSIZE, sent|wparam, 0 },
762     { WM_CREATE, sent },
763     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
764     { WM_SIZE, sent|wparam, SIZE_RESTORED },
765     { WM_MOVE, sent },
766     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
767     { WM_GETMINMAXINFO, sent },
768     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED  },
769     { WM_NCCALCSIZE, sent|wparam, TRUE },
770     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
771     { WM_MOVE, sent|defwinproc },
772     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
773     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
774     { 0 }
775 };
776 /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */
777 static const struct message WmShowMaxPopupResizedSeq[] = {
778     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
779     { WM_GETMINMAXINFO, sent },
780     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
781     { WM_NCCALCSIZE, sent|wparam, TRUE },
782     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
783     { HCBT_ACTIVATE, hook },
784     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
785     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
786     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
787     { WM_NCPAINT, sent|wparam|optional, 1 },
788     { WM_ERASEBKGND, sent|optional },
789     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
790     { WM_ACTIVATEAPP, sent|wparam, 1 },
791     { WM_NCACTIVATE, sent },
792     { WM_ACTIVATE, sent|wparam, 1 },
793     { HCBT_SETFOCUS, hook },
794     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
795     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
796     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
797     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
798     { WM_GETTEXT, sent|optional },
799     { WM_NCPAINT, sent|wparam|optional, 1 },
800     { WM_ERASEBKGND, sent|optional },
801     { WM_WINDOWPOSCHANGED, sent },
802     /* WinNT4.0 sends WM_MOVE */
803     { WM_MOVE, sent|defwinproc|optional },
804     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
805     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
806     { 0 }
807 };
808 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible popup window */
809 static const struct message WmShowMaxPopupSeq[] = {
810     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
811     { WM_GETMINMAXINFO, sent },
812     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
813     { WM_NCCALCSIZE, sent|wparam, TRUE },
814     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
815     { HCBT_ACTIVATE, hook },
816     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
817     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
818     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
819     { WM_NCPAINT, sent|wparam|optional, 1 },
820     { WM_ERASEBKGND, sent|optional },
821     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOMOVE|SWP_NOSIZE },
822     { WM_ACTIVATEAPP, sent|wparam, 1 },
823     { WM_NCACTIVATE, sent },
824     { WM_ACTIVATE, sent|wparam, 1 },
825     { HCBT_SETFOCUS, hook },
826     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
827     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
828     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
829     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
830     { WM_GETTEXT, sent|optional },
831     { WM_SYNCPAINT, sent|wparam|optional, 4 },
832     { WM_NCPAINT, sent|wparam|optional, 1 },
833     { WM_ERASEBKGND, sent|optional },
834     { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
835     { WM_ERASEBKGND, sent|defwinproc|optional },
836     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE },
837     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
838     { WM_SIZE, sent|defwinproc|optional },
839     { 0 }
840 };
841 /* CreateWindow(WS_VISIBLE) for popup window */
842 static const struct message WmCreatePopupSeq[] = {
843     { HCBT_CREATEWND, hook },
844     { WM_NCCREATE, sent },
845     { WM_NCCALCSIZE, sent|wparam, 0 },
846     { WM_CREATE, sent },
847     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
848     { WM_SIZE, sent|wparam, SIZE_RESTORED },
849     { WM_MOVE, sent },
850     { WM_SHOWWINDOW, sent|wparam, 1 },
851     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
852     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
853     { HCBT_ACTIVATE, hook },
854     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
855     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
856     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
857     { WM_NCPAINT, sent|wparam|optional, 1 },
858     { WM_ERASEBKGND, sent|optional },
859     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
860     { WM_ACTIVATEAPP, sent|wparam, 1 },
861     { WM_NCACTIVATE, sent },
862     { WM_ACTIVATE, sent|wparam, 1 },
863     { HCBT_SETFOCUS, hook },
864     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
865     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
866     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
867     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
868     { WM_GETTEXT, sent|optional },
869     { WM_SYNCPAINT, sent|wparam|optional, 4 },
870     { WM_NCPAINT, sent|wparam|optional, 1 },
871     { WM_ERASEBKGND, sent|optional },
872     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
873     { 0 }
874 };
875 /* ShowWindow(SW_SHOWMAXIMIZED) for a visible popup window */
876 static const struct message WmShowVisMaxPopupSeq[] = {
877     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
878     { WM_GETMINMAXINFO, sent },
879     { WM_GETTEXT, sent|optional },
880     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
881     { WM_GETTEXT, sent|optional },
882     { WM_NCCALCSIZE, sent|wparam, TRUE },
883     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
884     { WM_NCPAINT, sent|wparam|optional, 1 },
885     { WM_ERASEBKGND, sent|optional },
886     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
887     { WM_MOVE, sent|defwinproc },
888     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
889     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
890     { 0 }
891 };
892 /* CreateWindow (for a child popup window, not initially visible) */
893 static const struct message WmCreateChildPopupSeq[] = {
894     { HCBT_CREATEWND, hook },
895     { WM_NCCREATE, sent },
896     { WM_NCCALCSIZE, sent|wparam, 0 },
897     { WM_CREATE, sent },
898     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
899     { WM_SIZE, sent|wparam, SIZE_RESTORED },
900     { WM_MOVE, sent },
901     { 0 }
902 };
903 /* CreateWindow (for a popup window, not initially visible,
904  * which sets WS_VISIBLE in WM_CREATE handler)
905  */
906 static const struct message WmCreateInvisiblePopupSeq[] = {
907     { HCBT_CREATEWND, hook },
908     { WM_NCCREATE, sent },
909     { WM_NCCALCSIZE, sent|wparam, 0 },
910     { WM_CREATE, sent },
911     { WM_STYLECHANGING, sent },
912     { WM_STYLECHANGED, sent },
913     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
914     { WM_SIZE, sent|wparam, SIZE_RESTORED },
915     { WM_MOVE, sent },
916     { 0 }
917 };
918 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
919  * for a popup window with WS_VISIBLE style set
920  */
921 static const struct message WmShowVisiblePopupSeq_2[] = {
922     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
923     { 0 }
924 };
925 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
926  * for a popup window with WS_VISIBLE style set
927  */
928 static const struct message WmShowVisiblePopupSeq_3[] = {
929     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
930     { HCBT_ACTIVATE, hook },
931     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
932     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
933     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
934     { WM_NCACTIVATE, sent },
935     { WM_ACTIVATE, sent|wparam, 1 },
936     { HCBT_SETFOCUS, hook },
937     { WM_KILLFOCUS, sent|parent },
938     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
939     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
940     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
941     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
942     { WM_SETFOCUS, sent|defwinproc },
943     { WM_GETTEXT, sent|optional },
944     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_SHOWWINDOW },
945     { 0 }
946 };
947 /* CreateWindow (for a popup window with WS_VISIBLE style set and extreme location)
948  */
949 static const struct message WmShowPopupExtremeLocationSeq[] = {
950     { HCBT_CREATEWND, hook },
951     { WM_NCCREATE, sent },
952     { WM_NCCALCSIZE, sent|wparam, 0 },
953     { WM_CREATE, sent },
954     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
955     { WM_SIZE, sent|wparam, SIZE_RESTORED },
956     { WM_MOVE, sent },
957     { WM_SHOWWINDOW, sent|wparam, 1 },
958     { WM_WINDOWPOSCHANGING, sent },
959     { HCBT_ACTIVATE, hook },
960     { WM_WINDOWPOSCHANGING, sent|optional },
961     { WM_QUERYNEWPALETTE, sent|optional },
962     { WM_ACTIVATEAPP, sent },
963     { WM_NCACTIVATE, sent },
964     { WM_ACTIVATE, sent },
965     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
966     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
967     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
968     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
969     { HCBT_SETFOCUS, hook },
970     { WM_SETFOCUS, sent|defwinproc },
971     { WM_NCPAINT, sent|wparam, 1 },
972     { WM_ERASEBKGND, sent },
973     { WM_WINDOWPOSCHANGED, sent },
974     /* occasionally received on test machines */
975     { WM_NCPAINT, sent|optional },
976     { WM_ERASEBKGND, sent|optional },
977     { 0 }
978 };
979 /* CreateWindow (for a popup window with WS_VISIBLE style set)
980  */
981 static const struct message WmShowPopupFirstDrawSeq_1[] = {
982     { HCBT_CREATEWND, hook },
983     { WM_NCCREATE, sent },
984     { WM_NCCALCSIZE, sent|wparam, 0 },
985     { WM_CREATE, sent },
986     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
987     { WM_SIZE, sent|wparam, SIZE_RESTORED },
988     { WM_MOVE, sent },
989     { WM_SHOWWINDOW, sent|wparam, 1 },
990     { WM_WINDOWPOSCHANGING, sent },
991     { HCBT_ACTIVATE, hook },
992     { WM_WINDOWPOSCHANGING, sent|optional },
993     { WM_QUERYNEWPALETTE, sent|optional },
994     { WM_ACTIVATEAPP, sent },
995     { WM_NCACTIVATE, sent },
996     { WM_ACTIVATE, sent },
997     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
998     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
999     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1000     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1001     { HCBT_SETFOCUS, hook },
1002     { WM_SETFOCUS, sent|defwinproc },
1003     { WM_NCPAINT, sent|wparam, 1 },
1004     { WM_ERASEBKGND, sent },
1005     { WM_WINDOWPOSCHANGED, sent },
1006     { WM_PAINT, sent },
1007     /* occasionally received on test machines */
1008     { WM_NCPAINT, sent|beginpaint|optional },
1009     { WM_ERASEBKGND, sent|beginpaint|optional },
1010     { 0 }
1011 };
1012 /* CreateWindow (for a popup window that is shown with ShowWindow(SW_SHOWMAXIMIZED))
1013  */
1014 static const struct message WmShowPopupFirstDrawSeq_2[] = {
1015     { HCBT_CREATEWND, hook },
1016     { WM_NCCREATE, sent },
1017     { WM_NCCALCSIZE, sent|wparam, 0 },
1018     { WM_CREATE, sent },
1019     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1020     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1021     { WM_MOVE, sent },
1022     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1023     { WM_GETMINMAXINFO, sent },
1024     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_STATECHANGED|SWP_SHOWWINDOW|SWP_FRAMECHANGED  },
1025     { WM_NCCALCSIZE, sent|wparam, TRUE },
1026     { HCBT_ACTIVATE, hook },
1027     { WM_WINDOWPOSCHANGING, sent|optional },
1028     { WM_NCPAINT, sent|optional|wparam, 1 },
1029     { WM_ERASEBKGND, sent|optional },
1030     { WM_WINDOWPOSCHANGED, sent|optional },
1031     { WM_QUERYNEWPALETTE, sent|optional },
1032     { WM_ACTIVATEAPP, sent },
1033     { WM_NCACTIVATE, sent },
1034     { WM_ACTIVATE, sent },
1035     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1036     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1037     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1038     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1039     { HCBT_SETFOCUS, hook },
1040     { WM_SETFOCUS, sent|defwinproc },
1041     { WM_NCPAINT, sent|wparam, 1 },
1042     { WM_ERASEBKGND, sent },
1043     { WM_WINDOWPOSCHANGED, sent|optional },
1044     { WM_MOVE, sent|defwinproc },
1045     { WM_SIZE, sent|defwinproc, 0 },
1046     { WM_PAINT, sent},
1047     /* occasionally received on test machines */
1048     { WM_NCPAINT, sent|beginpaint|optional },
1049     { WM_ERASEBKGND, sent|beginpaint|optional },
1050     { 0 }
1051 };
1052 static const struct message WmFirstDrawSetWindowPosSeq1[] = {
1053     { HCBT_CREATEWND, hook },
1054     { WM_NCCREATE, sent },
1055     { WM_NCCALCSIZE, sent|wparam, 0 },
1056     { WM_CREATE, sent },
1057     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1058     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1059     { WM_MOVE, sent },
1060     { WM_WINDOWPOSCHANGING, sent },
1061     { HCBT_ACTIVATE, hook },
1062     { WM_WINDOWPOSCHANGING, sent|optional },
1063     { WM_QUERYNEWPALETTE, sent|optional },
1064     { WM_ACTIVATEAPP, sent },
1065     { WM_NCACTIVATE, sent },
1066     { WM_ACTIVATE, sent },
1067     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1068     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1069     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1070     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1071     { HCBT_SETFOCUS, hook },
1072     { WM_SETFOCUS, sent|defwinproc },
1073     { WM_NCPAINT, sent|wparam, 1 },
1074     { WM_ERASEBKGND, sent },
1075     { WM_WINDOWPOSCHANGED, sent },
1076     { WM_MOVE, sent|defwinproc },
1077     { 0 }
1078 };
1079 static const struct message WmFirstDrawSetWindowPosSeq2[] = {
1080     { HCBT_CREATEWND, hook },
1081     { WM_NCCREATE, sent },
1082     { WM_NCCALCSIZE, sent|wparam, 0 },
1083     { WM_CREATE, sent },
1084     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1085     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1086     { WM_MOVE, sent },
1087     { WM_WINDOWPOSCHANGING, sent },
1088     { HCBT_ACTIVATE, hook },
1089     { WM_QUERYNEWPALETTE, sent|optional },
1090     { WM_WINDOWPOSCHANGING, sent|optional },
1091     { WM_ACTIVATEAPP, sent },
1092     { WM_NCACTIVATE, sent },
1093     { WM_ACTIVATE, sent },
1094     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1095     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1096     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1097     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1098     { HCBT_SETFOCUS, hook },
1099     { WM_SETFOCUS, sent|defwinproc },
1100     { WM_WINDOWPOSCHANGED, sent },
1101     { WM_MOVE, sent|defwinproc },
1102     { 0 }
1103 };
1104 static const struct message WmFirstDrawSetWindowPosSeq3[] = {
1105     { HCBT_CREATEWND, hook },
1106     { WM_NCCREATE, sent },
1107     { WM_NCCALCSIZE, sent|wparam, 0 },
1108     { WM_CREATE, sent },
1109     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1110     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1111     { WM_MOVE, sent },
1112     { HCBT_ACTIVATE, hook|optional },
1113     /* Probably shouldn't happen, but not part of this test */
1114     { WM_QUERYNEWPALETTE, sent|optional },
1115     { WM_ACTIVATEAPP, sent|optional },
1116     { WM_NCACTIVATE, sent|optional },
1117     { WM_ACTIVATE, sent|optional },
1118     { HCBT_SETFOCUS, hook|optional },
1119     { WM_SETFOCUS, sent|defwinproc|optional },
1120     { 0 }
1121 };
1122 static const struct message WmFirstDrawSetWindowPosSeq4[] = {
1123     { HCBT_CREATEWND, hook },
1124     { WM_NCCREATE, sent },
1125     { WM_NCCALCSIZE, sent|wparam, 0 },
1126     { WM_CREATE, sent },
1127     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1128     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1129     { WM_MOVE, sent },
1130     { WM_WINDOWPOSCHANGING, sent },
1131     { HCBT_ACTIVATE, hook },
1132     { WM_WINDOWPOSCHANGING, sent|optional },
1133     { WM_QUERYNEWPALETTE, sent|optional },
1134     { WM_ACTIVATEAPP, sent },
1135     { WM_NCACTIVATE, sent },
1136     { WM_ACTIVATE, sent },
1137     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1138     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1139     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1140     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1141     { HCBT_SETFOCUS, hook },
1142     { WM_SETFOCUS, sent|defwinproc },
1143     { WM_NCPAINT, sent|wparam, 1 },
1144     { WM_ERASEBKGND, sent },
1145     { WM_WINDOWPOSCHANGED, sent },
1146     { 0 }
1147 };
1148 static const struct message WmFirstDrawSetWindowPosSeq5[] = {
1149     { HCBT_CREATEWND, hook },
1150     { WM_NCCREATE, sent },
1151     { WM_NCCALCSIZE, sent|wparam, 0 },
1152     { WM_CREATE, sent },
1153     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1154     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1155     { WM_MOVE, sent },
1156     { WM_WINDOWPOSCHANGING, sent },
1157     { HCBT_ACTIVATE, hook },
1158     { WM_WINDOWPOSCHANGING, sent|optional },
1159     { WM_QUERYNEWPALETTE, sent|optional },
1160     { WM_ACTIVATEAPP, sent },
1161     { WM_NCACTIVATE, sent },
1162     { WM_ACTIVATE, sent },
1163     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1164     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1165     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1166     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1167     { HCBT_SETFOCUS, hook },
1168     { WM_SETFOCUS, sent|defwinproc },
1169     { WM_WINDOWPOSCHANGED, sent },
1170     { 0 }
1171 };
1172 static const struct message WmFirstDrawChildSeq1[] = {
1173     { 0 }
1174 };
1175 static const struct message WmFirstDrawChildSeq2[] = {
1176     { WM_NCPAINT, sent|wparam, 1 },
1177     { WM_ERASEBKGND, sent },
1178     /* occasionally received on test machines */
1179     { WM_NCPAINT, sent|optional },
1180     { WM_ERASEBKGND, sent|optional },
1181     { 0 }
1182 };
1183 /* CreateWindow (for child window, not initially visible) */
1184 static const struct message WmCreateChildSeq[] = {
1185     { HCBT_CREATEWND, hook },
1186     { WM_NCCREATE, sent },
1187     /* child is inserted into parent's child list after WM_NCCREATE returns */
1188     { WM_NCCALCSIZE, sent|wparam, 0 },
1189     { WM_CREATE, sent },
1190     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1191     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1192     { WM_MOVE, sent },
1193     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1194     { 0 }
1195 };
1196 /* CreateWindow (for maximized child window, not initially visible) */
1197 static const struct message WmCreateMaximizedChildSeq[] = {
1198     { HCBT_CREATEWND, hook },
1199     { WM_NCCREATE, sent },
1200     { WM_NCCALCSIZE, sent|wparam, 0 },
1201     { WM_CREATE, sent },
1202     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1203     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1204     { WM_MOVE, sent },
1205     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1206     { WM_GETMINMAXINFO, sent },
1207     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
1208     { WM_NCCALCSIZE, sent|wparam, 1 },
1209     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1210     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1211     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1212     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1213     { 0 }
1214 };
1215 /* CreateWindow (for a child window, initially visible) */
1216 static const struct message WmCreateVisibleChildSeq[] = {
1217     { HCBT_CREATEWND, hook },
1218     { WM_NCCREATE, sent },
1219     /* child is inserted into parent's child list after WM_NCCREATE returns */
1220     { WM_NCCALCSIZE, sent|wparam, 0 },
1221     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1222     { WM_CREATE, sent },
1223     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1224     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1225     { WM_MOVE, sent },
1226     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1227     { WM_SHOWWINDOW, sent|wparam, 1 },
1228     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1229     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1230     { WM_ERASEBKGND, sent|parent|optional },
1231     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1232     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */
1233     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1234     { 0 }
1235 };
1236 /* ShowWindow(SW_SHOW) for a not visible child window */
1237 static const struct message WmShowChildSeq[] = {
1238     { WM_SHOWWINDOW, sent|wparam, 1 },
1239     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1240     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1241     { WM_ERASEBKGND, sent|parent|optional },
1242     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1243     { 0 }
1244 };
1245 /* ShowWindow(SW_HIDE) for a visible child window */
1246 static const struct message WmHideChildSeq[] = {
1247     { WM_SHOWWINDOW, sent|wparam, 0 },
1248     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1249     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1250     { WM_ERASEBKGND, sent|parent|optional },
1251     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1252     { 0 }
1253 };
1254 /* ShowWindow(SW_HIDE) for a visible child window checking all parent events*/
1255 static const struct message WmHideChildSeq2[] = {
1256     { WM_SHOWWINDOW, sent|wparam, 0 },
1257     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1258     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1259     { WM_ERASEBKGND, sent|parent|optional },
1260     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1261     { 0 }
1262 };
1263 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
1264  * for a not visible child window
1265  */
1266 static const struct message WmShowChildSeq_2[] = {
1267     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1268     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1269     { WM_CHILDACTIVATE, sent },
1270     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1271     { 0 }
1272 };
1273 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
1274  * for a not visible child window
1275  */
1276 static const struct message WmShowChildSeq_3[] = {
1277     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1278     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1279     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1280     { 0 }
1281 };
1282 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
1283  * for a visible child window with a caption
1284  */
1285 static const struct message WmShowChildSeq_4[] = {
1286     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1287     { WM_CHILDACTIVATE, sent },
1288     { 0 }
1289 };
1290 /* ShowWindow(SW_MINIMIZE) for child with invisible parent */
1291 static const struct message WmShowChildInvisibleParentSeq_1[] = {
1292     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1293     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1294     { WM_NCCALCSIZE, sent|wparam, 1 },
1295     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1296     { WM_CHILDACTIVATE, sent|optional },
1297     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1298     { WM_MOVE, sent|defwinproc },
1299     { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1300     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1301     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1302     /* FIXME: Wine creates an icon/title window while Windows doesn't */
1303     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1304     { WM_GETTEXT, sent|optional },
1305     { 0 }
1306 };
1307 /* repeated ShowWindow(SW_MINIMIZE) for child with invisible parent */
1308 static const struct message WmShowChildInvisibleParentSeq_1r[] = {
1309     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1310     { 0 }
1311 };
1312 /* ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1313 static const struct message WmShowChildInvisibleParentSeq_2[] = {
1314     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1315     { WM_GETMINMAXINFO, sent },
1316     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
1317     { WM_NCCALCSIZE, sent|wparam, 1 },
1318     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1319     { WM_CHILDACTIVATE, sent },
1320     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1321     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1322     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1323     { 0 }
1324 };
1325 /* repeated ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1326 static const struct message WmShowChildInvisibleParentSeq_2r[] = {
1327     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1328     { 0 }
1329 };
1330 /* ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1331 static const struct message WmShowChildInvisibleParentSeq_3[] = {
1332     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1333     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1334     { WM_NCCALCSIZE, sent|wparam, 1 },
1335     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1336     { WM_CHILDACTIVATE, sent },
1337     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1338     { WM_MOVE, sent|defwinproc },
1339     { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1340     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1341     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1342     /* FIXME: Wine creates an icon/title window while Windows doesn't */
1343     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1344     { WM_GETTEXT, sent|optional },
1345     { 0 }
1346 };
1347 /* repeated ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1348 static const struct message WmShowChildInvisibleParentSeq_3r[] = {
1349     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1350     { 0 }
1351 };
1352 /* ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1353 static const struct message WmShowChildInvisibleParentSeq_4[] = {
1354     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1355     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
1356     { WM_NCCALCSIZE, sent|wparam, 1 },
1357     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1358     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1359     { WM_MOVE, sent|defwinproc },
1360     { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1361     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1362     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1363     /* FIXME: Wine creates an icon/title window while Windows doesn't */
1364     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1365     { WM_GETTEXT, sent|optional },
1366     { 0 }
1367 };
1368 /* repeated ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1369 static const struct message WmShowChildInvisibleParentSeq_4r[] = {
1370     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1371     { 0 }
1372 };
1373 /* ShowWindow(SW_SHOW) for child with invisible parent */
1374 static const struct message WmShowChildInvisibleParentSeq_5[] = {
1375     { WM_SHOWWINDOW, sent|wparam, 1 },
1376     { 0 }
1377 };
1378 /* ShowWindow(SW_HIDE) for child with invisible parent */
1379 static const struct message WmHideChildInvisibleParentSeq[] = {
1380     { WM_SHOWWINDOW, sent|wparam, 0 },
1381     { 0 }
1382 };
1383 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
1384 static const struct message WmShowChildInvisibleParentSeq_6[] = {
1385     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1386     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1387     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1388     { 0 }
1389 };
1390 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
1391 static const struct message WmHideChildInvisibleParentSeq_2[] = {
1392     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1393     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1394     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1395     { 0 }
1396 };
1397 /* DestroyWindow for a visible child window */
1398 static const struct message WmDestroyChildSeq[] = {
1399     { HCBT_DESTROYWND, hook },
1400     { 0x0090, sent|optional },
1401     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1402     { WM_SHOWWINDOW, sent|wparam, 0 },
1403     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1404     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1405     { WM_ERASEBKGND, sent|parent|optional },
1406     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1407     { HCBT_SETFOCUS, hook }, /* set focus to a parent */
1408     { WM_KILLFOCUS, sent },
1409     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1410     { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
1411     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1412     { WM_SETFOCUS, sent|parent },
1413     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1414     { WM_DESTROY, sent },
1415     { WM_DESTROY, sent|optional }, /* some other (IME?) window */
1416     { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
1417     { WM_NCDESTROY, sent },
1418     { 0 }
1419 };
1420 /* visible child window destroyed by thread exit */
1421 static const struct message WmExitThreadSeq[] = {
1422     { WM_NCDESTROY, sent },  /* actually in grandchild */
1423     { WM_PAINT, sent|parent },
1424     { WM_ERASEBKGND, sent|parent|beginpaint },
1425     { 0 }
1426 };
1427 /* DestroyWindow for a visible child window with invisible parent */
1428 static const struct message WmDestroyInvisibleChildSeq[] = {
1429     { HCBT_DESTROYWND, hook },
1430     { 0x0090, sent|optional },
1431     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1432     { WM_SHOWWINDOW, sent|wparam, 0 },
1433     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1434     { WM_DESTROY, sent },
1435     { WM_NCDESTROY, sent },
1436     { 0 }
1437 };
1438 /* Resizing child window with MoveWindow (32) */
1439 static const struct message WmResizingChildWithMoveWindowSeq[] = {
1440     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
1441     { WM_NCCALCSIZE, sent|wparam, 1 },
1442     { WM_ERASEBKGND, sent|parent|optional },
1443     { WM_ERASEBKGND, sent|optional },
1444     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE },
1445     { WM_MOVE, sent|defwinproc },
1446     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1447     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1448     { 0 }
1449 };
1450 /* Creation of a custom dialog (32) */
1451 static const struct message WmCreateCustomDialogSeq[] = {
1452     { HCBT_CREATEWND, hook },
1453     { WM_GETMINMAXINFO, sent },
1454     { WM_NCCREATE, sent },
1455     { WM_NCCALCSIZE, sent|wparam, 0 },
1456     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1457     { WM_CREATE, sent },
1458     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1459     { WM_NOTIFYFORMAT, sent|optional },
1460     { WM_QUERYUISTATE, sent|optional },
1461     { WM_WINDOWPOSCHANGING, sent|optional },
1462     { WM_GETMINMAXINFO, sent|optional },
1463     { WM_NCCALCSIZE, sent|optional },
1464     { WM_WINDOWPOSCHANGED, sent|optional },
1465     { WM_SHOWWINDOW, sent|wparam, 1 },
1466     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1467     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1468     { HCBT_ACTIVATE, hook },
1469     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1470 
1471 
1472     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1473 
1474     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1475 
1476     { WM_NCACTIVATE, sent },
1477     { WM_GETTEXT, sent|optional|defwinproc },
1478     { WM_GETTEXT, sent|optional|defwinproc },
1479     { WM_GETTEXT, sent|optional|defwinproc },
1480     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
1481     { WM_ACTIVATE, sent|wparam, 1 },
1482     { WM_GETTEXT, sent|optional },
1483     { WM_KILLFOCUS, sent|parent },
1484     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1485     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1486     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1487     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1488     { WM_SETFOCUS, sent },
1489     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1490     { WM_NCPAINT, sent|wparam, 1 },
1491     { WM_GETTEXT, sent|optional|defwinproc },
1492     { WM_GETTEXT, sent|optional|defwinproc },
1493     { WM_ERASEBKGND, sent },
1494     { WM_CTLCOLORDLG, sent|optional|defwinproc },
1495     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1496     { WM_GETTEXT, sent|optional },
1497     { WM_GETTEXT, sent|optional },
1498     { WM_NCCALCSIZE, sent|optional },
1499     { WM_NCPAINT, sent|optional },
1500     { WM_GETTEXT, sent|optional|defwinproc },
1501     { WM_GETTEXT, sent|optional|defwinproc },
1502     { WM_ERASEBKGND, sent|optional },
1503     { WM_CTLCOLORDLG, sent|optional|defwinproc },
1504     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1505     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1506     { WM_MOVE, sent },
1507     { 0 }
1508 };
1509 /* Calling EndDialog for a custom dialog (32) */
1510 static const struct message WmEndCustomDialogSeq[] = {
1511     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1512     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1513     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1514     { WM_GETTEXT, sent|optional },
1515     { HCBT_ACTIVATE, hook },
1516     { WM_NCACTIVATE, sent|wparam, 0 },
1517     { WM_GETTEXT, sent|optional|defwinproc },
1518     { WM_GETTEXT, sent|optional|defwinproc },
1519     { WM_ACTIVATE, sent|wparam, 0 },
1520     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1521     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1522     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1523     { WM_GETTEXT, sent|optional|defwinproc },
1524     { WM_GETTEXT, sent|optional|defwinproc },
1525     { HCBT_SETFOCUS, hook },
1526     { WM_KILLFOCUS, sent },
1527     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1528     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1529     { WM_IME_NOTIFY, sent|wparam|optional, 1 },
1530     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1531     { WM_SETFOCUS, sent|parent|defwinproc },
1532     { 0 }
1533 };
1534 /* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
1535 static const struct message WmShowCustomDialogSeq[] = {
1536     { WM_SHOWWINDOW, sent|wparam, 1 },
1537     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1538     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1539     { HCBT_ACTIVATE, hook },
1540     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1541 
1542     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1543 
1544     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1545     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
1546     { WM_NCACTIVATE, sent },
1547     { WM_ACTIVATE, sent|wparam, 1 },
1548     { WM_GETTEXT, sent|optional },
1549 
1550     { WM_KILLFOCUS, sent|parent },
1551     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1552     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1553     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1554     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1555     { WM_SETFOCUS, sent },
1556     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1557     { WM_NCPAINT, sent|wparam, 1 },
1558     { WM_ERASEBKGND, sent },
1559     { WM_CTLCOLORDLG, sent|defwinproc },
1560     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1561     { 0 }
1562 };
1563 /* Creation and destruction of a modal dialog (32) */
1564 static const struct message WmModalDialogSeq[] = {
1565     { WM_CANCELMODE, sent|parent },
1566     { HCBT_SETFOCUS, hook },
1567     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1568     { WM_KILLFOCUS, sent|parent },
1569     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1570     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1571     { WM_ENABLE, sent|parent|wparam, 0 },
1572     { HCBT_CREATEWND, hook },
1573     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1574     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1575     { WM_SETFONT, sent },
1576     { WM_INITDIALOG, sent },
1577     { WM_CHANGEUISTATE, sent|optional },
1578     { WM_UPDATEUISTATE, sent|optional },
1579     { WM_SHOWWINDOW, sent },
1580     { HCBT_ACTIVATE, hook },
1581     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1582     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1583     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1584     { WM_NCACTIVATE, sent },
1585     { WM_GETTEXT, sent|optional },
1586     { WM_ACTIVATE, sent|wparam, 1 },
1587     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1588     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1589     { WM_NCPAINT, sent|optional },
1590     { WM_GETTEXT, sent|optional },
1591     { WM_ERASEBKGND, sent|optional },
1592     { WM_CTLCOLORDLG, sent|optional },
1593     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1594     { WM_GETTEXT, sent|optional },
1595     { WM_NCCALCSIZE, sent|optional },
1596     { WM_NCPAINT, sent|optional },
1597     { WM_GETTEXT, sent|optional },
1598     { WM_ERASEBKGND, sent|optional },
1599     { WM_CTLCOLORDLG, sent|optional },
1600     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1601     { WM_PAINT, sent|optional },
1602     { WM_CTLCOLORBTN, sent|optional },
1603     { WM_GETTITLEBARINFOEX, sent|optional },
1604     { WM_ENTERIDLE, sent|parent|optional },
1605     { WM_ENTERIDLE, sent|parent|optional },
1606     { WM_ENTERIDLE, sent|parent|optional },
1607     { WM_ENTERIDLE, sent|parent|optional },
1608     { WM_ENTERIDLE, sent|parent|optional },
1609     { WM_ENTERIDLE, sent|parent|optional },
1610     { WM_ENTERIDLE, sent|parent|optional },
1611     { WM_ENTERIDLE, sent|parent|optional },
1612     { WM_ENTERIDLE, sent|parent|optional },
1613     { WM_ENTERIDLE, sent|parent|optional },
1614     { WM_ENTERIDLE, sent|parent|optional },
1615     { WM_ENTERIDLE, sent|parent|optional },
1616     { WM_ENTERIDLE, sent|parent|optional },
1617     { WM_ENTERIDLE, sent|parent|optional },
1618     { WM_ENTERIDLE, sent|parent|optional },
1619     { WM_ENTERIDLE, sent|parent|optional },
1620     { WM_ENTERIDLE, sent|parent|optional },
1621     { WM_ENTERIDLE, sent|parent|optional },
1622     { WM_ENTERIDLE, sent|parent|optional },
1623     { WM_ENTERIDLE, sent|parent|optional },
1624     { WM_TIMER, sent },
1625     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1626     { WM_ENABLE, sent|parent|wparam, 1 },
1627     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1628     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1629     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1630     { WM_GETTEXT, sent|optional },
1631     { HCBT_ACTIVATE, hook },
1632     { WM_NCACTIVATE, sent|wparam, 0 },
1633     { WM_GETTEXT, sent|optional },
1634     { WM_ACTIVATE, sent|wparam, 0 },
1635     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1636     { WM_WINDOWPOSCHANGING, sent|optional },
1637     { WM_WINDOWPOSCHANGED, sent|optional },
1638     { HCBT_SETFOCUS, hook },
1639     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1640     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1641     { WM_SETFOCUS, sent|parent|defwinproc },
1642     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 },
1643     { HCBT_DESTROYWND, hook },
1644     { 0x0090, sent|optional },
1645     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1646     { WM_DESTROY, sent },
1647     { WM_NCDESTROY, sent },
1648     { 0 }
1649 };
1650 static const struct message WmModalDialogSeq_2[] = {
1651     { WM_CANCELMODE, sent },
1652     { HCBT_SETFOCUS, hook },
1653     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1654     { WM_KILLFOCUS, sent },
1655     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1656     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1657     { WM_ENABLE, sent|wparam, 0 },
1658     { HCBT_CREATEWND, hook },
1659     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1660     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1661     { WM_SETFONT, sent },
1662     { WM_INITDIALOG, sent },
1663     { WM_CHANGEUISTATE, sent|optional },
1664     { WM_UPDATEUISTATE, sent|optional },
1665     { WM_ENABLE, sent|wparam, 1 },
1666     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1667     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1668     { WM_CHANGEUISTATE, sent|optional },
1669     { WM_UPDATEUISTATE, sent|optional },
1670     { HCBT_DESTROYWND, hook },
1671     { 0x0090, sent|optional },
1672     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1673     { WM_DESTROY, sent },
1674     { WM_NCDESTROY, sent },
1675     { 0 }
1676 };
1677 /* SetMenu for NonVisible windows with size change*/
1678 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
1679     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1680     { WM_NCCALCSIZE, sent|wparam, 1 },
1681     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1682     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
1683     { WM_MOVE, sent|defwinproc },
1684     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1685     { WM_NCCALCSIZE,sent|wparam|optional, 1 }, /* XP */
1686     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1687     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1688     { WM_GETTEXT, sent|optional },
1689     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1690     { 0 }
1691 };
1692 /* SetMenu for NonVisible windows with no size change */
1693 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
1694     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1695     { WM_NCCALCSIZE, sent|wparam, 1 },
1696     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1697     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1698     { 0 }
1699 };
1700 /* SetMenu for Visible windows with size change */
1701 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
1702     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1703     { WM_NCCALCSIZE, sent|wparam, 1 },
1704     { 0x0093, sent|defwinproc|optional },
1705     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1706     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1707     { 0x0093, sent|defwinproc|optional },
1708     { 0x0093, sent|defwinproc|optional },
1709     { 0x0091, sent|defwinproc|optional },
1710     { 0x0092, sent|defwinproc|optional },
1711     { WM_GETTEXT, sent|defwinproc|optional },
1712     { WM_ERASEBKGND, sent|optional },
1713     { WM_ACTIVATE, sent|optional },
1714     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1715     { WM_MOVE, sent|defwinproc },
1716     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1717     { 0x0093, sent|optional },
1718     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1719     { 0x0093, sent|defwinproc|optional },
1720     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1721     { 0x0093, sent|defwinproc|optional },
1722     { 0x0093, sent|defwinproc|optional },
1723     { 0x0091, sent|defwinproc|optional },
1724     { 0x0092, sent|defwinproc|optional },
1725     { WM_ERASEBKGND, sent|optional },
1726     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1727     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1728     { 0 }
1729 };
1730 /* SetMenu for Visible windows with no size change */
1731 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
1732     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1733     { WM_NCCALCSIZE, sent|wparam, 1 },
1734     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1735     { WM_GETTEXT, sent|defwinproc|optional },
1736     { WM_ERASEBKGND, sent|optional },
1737     { WM_ACTIVATE, sent|optional },
1738     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1739     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1740     { 0 }
1741 };
1742 /* DrawMenuBar for a visible window */
1743 static const struct message WmDrawMenuBarSeq[] =
1744 {
1745     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1746     { WM_NCCALCSIZE, sent|wparam, 1 },
1747     { 0x0093, sent|defwinproc|optional },
1748     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1749     { 0x0093, sent|defwinproc|optional },
1750     { 0x0093, sent|defwinproc|optional },
1751     { 0x0091, sent|defwinproc|optional },
1752     { 0x0092, sent|defwinproc|optional },
1753     { WM_GETTEXT, sent|defwinproc|optional },
1754     { WM_ERASEBKGND, sent|optional },
1755     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1756     { 0x0093, sent|optional },
1757     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1758     { 0 }
1759 };
1760 
1761 static const struct message WmSetRedrawFalseSeq[] =
1762 {
1763     { WM_SETREDRAW, sent|wparam, 0 },
1764     { 0 }
1765 };
1766 
1767 static const struct message WmSetRedrawTrueSeq[] =
1768 {
1769     { WM_SETREDRAW, sent|wparam, 1 },
1770     { 0 }
1771 };
1772 
1773 static const struct message WmEnableWindowSeq_1[] =
1774 {
1775     { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1776     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1777     { HCBT_SETFOCUS, hook|optional },
1778     { WM_KILLFOCUS, sent|optional },
1779     { WM_ENABLE, sent|wparam|lparam, FALSE, 0 },
1780     { 0 }
1781 };
1782 
1783 static const struct message WmEnableWindowSeq_2[] =
1784 {
1785     { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1786     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1787     { 0 }
1788 };
1789 
1790 static const struct message WmEnableWindowSeq_3[] =
1791 {
1792     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1793     { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
1794     { 0 }
1795 };
1796 
1797 static const struct message WmEnableWindowSeq_4[] =
1798 {
1799     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1800     { 0 }
1801 };
1802 
1803 static const struct message WmGetScrollRangeSeq[] =
1804 {
1805     { SBM_GETRANGE, sent },
1806     { 0 }
1807 };
1808 static const struct message WmGetScrollInfoSeq[] =
1809 {
1810     { SBM_GETSCROLLINFO, sent },
1811     { 0 }
1812 };
1813 static const struct message WmSetScrollRangeSeq[] =
1814 {
1815     /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
1816        sends SBM_SETSCROLLINFO.
1817      */
1818     { SBM_SETSCROLLINFO, sent },
1819     { 0 }
1820 };
1821 /* SetScrollRange for a window without a non-client area */
1822 static const struct message WmSetScrollRangeHSeq_empty[] =
1823 {
1824     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_HSCROLL, 0 },
1825     { 0 }
1826 };
1827 static const struct message WmSetScrollRangeVSeq_empty[] =
1828 {
1829     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_VSCROLL, 0 },
1830     { 0 }
1831 };
1832 static const struct message WmSetScrollRangeHVSeq[] =
1833 {
1834     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1835     { WM_NCCALCSIZE, sent|wparam, 1 },
1836     { WM_GETTEXT, sent|defwinproc|optional },
1837     { WM_ERASEBKGND, sent|optional },
1838     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1839     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1840     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1841     { 0 }
1842 };
1843 /* SetScrollRange for a window with a non-client area */
1844 static const struct message WmSetScrollRangeHV_NC_Seq[] =
1845 {
1846     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1847     { WM_NCCALCSIZE, sent|wparam, 1 },
1848     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1849     { WM_NCPAINT, sent|optional },
1850     { WM_STYLECHANGING, sent|defwinproc|optional },
1851     { WM_STYLECHANGED, sent|defwinproc|optional },
1852     { WM_STYLECHANGING, sent|defwinproc|optional },
1853     { WM_STYLECHANGED, sent|defwinproc|optional },
1854     { WM_STYLECHANGING, sent|defwinproc|optional },
1855     { WM_STYLECHANGED, sent|defwinproc|optional },
1856     { WM_STYLECHANGING, sent|defwinproc|optional },
1857     { WM_STYLECHANGED, sent|defwinproc|optional },
1858     { WM_GETTEXT, sent|defwinproc|optional },
1859     { WM_GETTEXT, sent|defwinproc|optional },
1860     { WM_ERASEBKGND, sent|optional },
1861     { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
1862     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOCLIENTSIZE },
1863     { WM_SIZE, sent|defwinproc|optional },
1864     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1865     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1866     { WM_GETTEXT, sent|optional },
1867     { WM_GETTEXT, sent|optional },
1868     { WM_GETTEXT, sent|optional },
1869     { WM_GETTEXT, sent|optional },
1870     { 0 }
1871 };
1872 /* test if we receive the right sequence of messages */
1873 /* after calling ShowWindow( SW_SHOWNA) */
1874 static const struct message WmSHOWNAChildInvisParInvis[] = {
1875     { WM_SHOWWINDOW, sent|wparam, 1 },
1876     { 0 }
1877 };
1878 static const struct message WmSHOWNAChildVisParInvis[] = {
1879     { WM_SHOWWINDOW, sent|wparam, 1 },
1880     { 0 }
1881 };
1882 static const struct message WmSHOWNAChildVisParVis[] = {
1883     { WM_SHOWWINDOW, sent|wparam, 1 },
1884     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1885     { 0 }
1886 };
1887 static const struct message WmSHOWNAChildInvisParVis[] = {
1888     { WM_SHOWWINDOW, sent|wparam, 1 },
1889     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1890     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1891     { WM_ERASEBKGND, sent|optional },
1892     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOCLIENTMOVE },
1893     { 0 }
1894 };
1895 static const struct message WmSHOWNATopVisible[] = {
1896     { WM_SHOWWINDOW, sent|wparam, 1 },
1897     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1898     { WM_NCPAINT, sent|wparam|optional, 1 },
1899     { WM_GETTEXT, sent|defwinproc|optional },
1900     { WM_ERASEBKGND, sent|optional },
1901     { WM_WINDOWPOSCHANGED, sent|optional },
1902     { 0 }
1903 };
1904 static const struct message WmSHOWNATopInvisible[] = {
1905     { WM_NOTIFYFORMAT, sent|optional },
1906     { WM_QUERYUISTATE, sent|optional },
1907     { WM_WINDOWPOSCHANGING, sent|optional },
1908     { WM_GETMINMAXINFO, sent|optional },
1909     { WM_NCCALCSIZE, sent|optional },
1910     { WM_WINDOWPOSCHANGED, sent|optional },
1911     { WM_SHOWWINDOW, sent|wparam, 1 },
1912     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1913     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1914     { WM_NCPAINT, sent|wparam|optional, 1 },
1915     { WM_GETTEXT, sent|defwinproc|optional },
1916     { WM_ERASEBKGND, sent|optional },
1917     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1918     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1919     { WM_NCPAINT, sent|wparam|optional, 1 },
1920     { WM_ERASEBKGND, sent|optional },
1921     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1922     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1923     { WM_MOVE, sent },
1924     { 0 }
1925 };
1926 
1927 static const struct message WmTrackPopupMenu[] = {
1928     { HCBT_CREATEWND, hook },
1929     { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1930     { WM_INITMENU, sent|lparam, 0, 0 },
1931     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1932     { 0x0093, sent|optional },
1933     { 0x0094, sent|optional },
1934     { 0x0094, sent|optional },
1935     { WM_ENTERIDLE, sent|wparam, 2 },
1936     { WM_CAPTURECHANGED, sent },
1937     { HCBT_DESTROYWND, hook },
1938     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1939     { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
1940     { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1941     { 0 }
1942 };
1943 
1944 static const struct message WmTrackPopupMenuEsc[] = {
1945     { 0 }
1946 };
1947 
1948 static const struct message WmTrackPopupMenuCapture[] = {
1949     { HCBT_CREATEWND, hook },
1950     { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1951     { WM_CAPTURECHANGED, sent },
1952     { WM_INITMENU, sent|lparam, 0, 0 },
1953     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1954     { 0x0093, sent|optional },
1955     { 0x0094, sent|optional },
1956     { 0x0094, sent|optional },
1957     { WM_ENTERIDLE, sent|wparam, 2 },
1958     { WM_CAPTURECHANGED, sent },
1959     { HCBT_DESTROYWND, hook },
1960     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1961     { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
1962     { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1963     { 0 }
1964 };
1965 
1966 static const struct message WmTrackPopupMenuEmpty[] = {
1967     { HCBT_CREATEWND, hook },
1968     { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1969     { WM_INITMENU, sent|lparam, 0, 0 },
1970     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1971     { 0x0093, sent|optional },
1972     { 0x0094, sent|optional },
1973     { 0x0094, sent|optional },
1974     { WM_CAPTURECHANGED, sent },
1975     { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1976     { HCBT_DESTROYWND, hook },
1977     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1978     { 0 }
1979 };
1980 
1981 static const struct message WmTrackPopupMenuAbort[] = {
1982     { HCBT_CREATEWND, hook },
1983     { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1984     { WM_INITMENU, sent|lparam, 0, 0 },
1985     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1986     { 0x0093, sent|optional },
1987     { 0x0094, sent|optional },
1988     { 0x0094, sent|optional },
1989     { WM_CAPTURECHANGED, sent },
1990     { HCBT_DESTROYWND, hook },
1991     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1992     { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
1993     { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1994     { 0 }
1995 };
1996 
1997 static BOOL after_end_dialog, test_def_id, paint_loop_done;
1998 static int sequence_cnt, sequence_size;
1999 static struct recvd_message* sequence;
2000 static int log_all_parent_messages;
2001 static CRITICAL_SECTION sequence_cs;
2002 
2003 /* user32 functions */
2004 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
2005 static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO);
2006 static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG);
2007 static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO);
2008 static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD);
2009 static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*);
2010 static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
2011 static BOOL (WINAPI *pGetMonitorInfoA)(HMONITOR,LPMONITORINFO);
2012 static HMONITOR (WINAPI *pMonitorFromPoint)(POINT,DWORD);
2013 static BOOL (WINAPI *pUpdateLayeredWindow)(HWND,HDC,POINT*,SIZE*,HDC,POINT*,COLORREF,BLENDFUNCTION*,DWORD);
2014 static UINT_PTR (WINAPI *pSetSystemTimer)(HWND, UINT_PTR, UINT, TIMERPROC);
2015 static UINT_PTR (WINAPI *pKillSystemTimer)(HWND, UINT_PTR);
2016 static UINT_PTR (WINAPI *pSetCoalescableTimer)(HWND, UINT_PTR, UINT, TIMERPROC, ULONG);
2017 /* kernel32 functions */
2018 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
2019 
2020 static void init_procs(void)
2021 {
2022     HMODULE user32 = GetModuleHandleA("user32.dll");
2023     HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
2024 
2025 #define GET_PROC(dll, func) \
2026     p ## func = (void*)GetProcAddress(dll, #func); \
2027     if(!p ## func) { \
2028       trace("GetProcAddress(%s) failed\n", #func); \
2029     }
2030 
2031     GET_PROC(user32, GetAncestor)
2032     GET_PROC(user32, GetMenuInfo)
2033     GET_PROC(user32, NotifyWinEvent)
2034     GET_PROC(user32, SetMenuInfo)
2035     GET_PROC(user32, SetWinEventHook)
2036     GET_PROC(user32, TrackMouseEvent)
2037     GET_PROC(user32, UnhookWinEvent)
2038     GET_PROC(user32, GetMonitorInfoA)
2039     GET_PROC(user32, MonitorFromPoint)
2040     GET_PROC(user32, UpdateLayeredWindow)
2041     GET_PROC(user32, SetSystemTimer)
2042     GET_PROC(user32, KillSystemTimer)
2043     GET_PROC(user32, SetCoalescableTimer)
2044 
2045     GET_PROC(kernel32, GetCPInfoExA)
2046 
2047 #undef GET_PROC
2048 }
2049 
2050 static const char *get_winpos_flags(UINT flags)
2051 {
2052     static char buffer[300];
2053 
2054     buffer[0] = 0;
2055 #define DUMP(flag) do { if (flags & flag) { strcat( buffer, "|" #flag ); flags &= ~flag; } } while(0)
2056     DUMP( SWP_SHOWWINDOW );
2057     DUMP( SWP_HIDEWINDOW );
2058     DUMP( SWP_NOACTIVATE );
2059     DUMP( SWP_FRAMECHANGED );
2060     DUMP( SWP_NOCOPYBITS );
2061     DUMP( SWP_NOOWNERZORDER );
2062     DUMP( SWP_NOSENDCHANGING );
2063     DUMP( SWP_DEFERERASE );
2064     DUMP( SWP_ASYNCWINDOWPOS );
2065     DUMP( SWP_NOZORDER );
2066     DUMP( SWP_NOREDRAW );
2067     DUMP( SWP_NOSIZE );
2068     DUMP( SWP_NOMOVE );
2069     DUMP( SWP_NOCLIENTSIZE );
2070     DUMP( SWP_NOCLIENTMOVE );
2071     if (flags) sprintf(buffer + strlen(buffer),"|0x%04x", flags);
2072     return buffer + 1;
2073 #undef DUMP
2074 }
2075 
2076 static BOOL ignore_message( UINT message )
2077 {
2078     /* these are always ignored */
2079     return (message >= 0xc000 ||
2080             message == WM_GETICON ||
2081             message == WM_GETOBJECT ||
2082             message == WM_TIMECHANGE ||
2083             message == WM_DISPLAYCHANGE ||
2084             message == WM_DEVICECHANGE ||
2085             message == WM_DWMNCRENDERINGCHANGED);
2086 }
2087 
2088 static unsigned hash_Ly_W(const WCHAR *str)
2089 {
2090     unsigned hash = 0;
2091 
2092     for (; *str; str++)
2093         hash = hash * 1664525u + (unsigned char)(*str) + 1013904223u;
2094 
2095     return hash;
2096 }
2097 
2098 static unsigned hash_Ly(const char *str)
2099 {
2100     unsigned hash = 0;
2101 
2102     for (; *str; str++)
2103         hash = hash * 1664525u + (unsigned char)(*str) + 1013904223u;
2104 
2105     return hash;
2106 }
2107 
2108 #define add_message(msg) add_message_(__LINE__,msg);
2109 static void add_message_(int line, const struct recvd_message *msg)
2110 {
2111     struct recvd_message *seq;
2112 
2113     EnterCriticalSection( &sequence_cs );
2114     if (!sequence)
2115     {
2116 	sequence_size = 10;
2117 	sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof(*sequence) );
2118     }
2119     if (sequence_cnt == sequence_size)
2120     {
2121 	sequence_size *= 2;
2122 	sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof(*sequence) );
2123     }
2124     assert(sequence);
2125 
2126     seq = &sequence[sequence_cnt++];
2127     seq->hwnd = msg->hwnd;
2128     seq->message = msg->message;
2129     seq->flags = msg->flags;
2130     seq->wParam = msg->wParam;
2131     seq->lParam = msg->lParam;
2132     seq->line   = line;
2133     seq->descr  = msg->descr;
2134     seq->output[0] = 0;
2135     LeaveCriticalSection( &sequence_cs );
2136 
2137     if (msg->descr)
2138     {
2139         if (msg->flags & hook)
2140         {
2141             static const char * const CBT_code_name[10] =
2142             {
2143                 "HCBT_MOVESIZE",
2144                 "HCBT_MINMAX",
2145                 "HCBT_QS",
2146                 "HCBT_CREATEWND",
2147                 "HCBT_DESTROYWND",
2148                 "HCBT_ACTIVATE",
2149                 "HCBT_CLICKSKIPPED",
2150                 "HCBT_KEYSKIPPED",
2151                 "HCBT_SYSCOMMAND",
2152                 "HCBT_SETFOCUS"
2153             };
2154             const char *code_name = (msg->message <= HCBT_SETFOCUS) ? CBT_code_name[msg->message] : "Unknown";
2155 
2156             sprintf( seq->output, "%s: hook %d (%s) wp %08lx lp %08lx",
2157                      msg->descr, msg->message, code_name, msg->wParam, msg->lParam );
2158         }
2159         else if (msg->flags & winevent_hook)
2160         {
2161             sprintf( seq->output, "%s: winevent %p %08x %08lx %08lx",
2162                      msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
2163         }
2164         else
2165         {
2166             switch (msg->message)
2167             {
2168             case WM_WINDOWPOSCHANGING:
2169             case WM_WINDOWPOSCHANGED:
2170             {
2171                 WINDOWPOS *winpos = (WINDOWPOS *)msg->lParam;
2172 
2173                 sprintf( seq->output, "%s: %p WM_WINDOWPOS%s wp %08lx lp %08lx after %p x %d y %d cx %d cy %d flags %s",
2174                           msg->descr, msg->hwnd,
2175                           (msg->message == WM_WINDOWPOSCHANGING) ? "CHANGING" : "CHANGED",
2176                           msg->wParam, msg->lParam, winpos->hwndInsertAfter,
2177                           winpos->x, winpos->y, winpos->cx, winpos->cy,
2178                           get_winpos_flags(winpos->flags) );
2179 
2180                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2181                  * in the high word for internal purposes
2182                  */
2183                 seq->wParam = winpos->flags & 0xffff;
2184                 /* We are not interested in the flags that don't match under XP and Win9x */
2185                 seq->wParam &= ~SWP_NOZORDER;
2186                 break;
2187             }
2188 
2189             case WM_DRAWITEM:
2190             {
2191                 DRAW_ITEM_STRUCT di;
2192                 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)msg->lParam;
2193 
2194                 sprintf( seq->output, "%s: %p WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x",
2195                          msg->descr, msg->hwnd, dis->CtlType, dis->CtlID,
2196                          dis->itemID, dis->itemAction, dis->itemState);
2197 
2198                 di.u.lp = 0;
2199                 di.u.item.type = dis->CtlType;
2200                 di.u.item.ctl_id = dis->CtlID;
2201                 if (dis->CtlType == ODT_LISTBOX ||
2202                     dis->CtlType == ODT_COMBOBOX ||
2203                     dis->CtlType == ODT_MENU)
2204                     di.u.item.item_id = dis->itemID;
2205                 di.u.item.action = dis->itemAction;
2206                 di.u.item.state = dis->itemState;
2207 
2208                 seq->lParam = di.u.lp;
2209                 break;
2210             }
2211 
2212             case WM_MEASUREITEM:
2213             {
2214                 MEASURE_ITEM_STRUCT mi;
2215                 MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *)msg->lParam;
2216                 BOOL is_unicode_data = TRUE;
2217 
2218                 sprintf( seq->output, "%s: %p WM_MEASUREITEM: CtlType %#x, CtlID %#x, itemID %#x, itemData %#lx",
2219                          msg->descr, msg->hwnd, mis->CtlType, mis->CtlID,
2220                          mis->itemID, mis->itemData);
2221 
2222                 if (mis->CtlType == ODT_LISTBOX)
2223                 {
2224                     HWND ctrl = GetDlgItem(msg->hwnd, mis->CtlID);
2225                     is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS;
2226                 }
2227 
2228                 mi.u.wp = 0;
2229                 mi.u.item.CtlType = mis->CtlType;
2230                 mi.u.item.CtlID = mis->CtlID;
2231                 mi.u.item.itemID = mis->itemID;
2232                 mi.u.item.wParam = msg->wParam;
2233                 seq->wParam = mi.u.wp;
2234                 if (is_unicode_data)
2235                     seq->lParam = mis->itemData ? hash_Ly_W((const WCHAR *)mis->itemData) : 0;
2236                 else
2237                     seq->lParam = mis->itemData ? hash_Ly((const char *)mis->itemData) : 0;
2238                 break;
2239             }
2240 
2241             case WM_COMPAREITEM:
2242             {
2243                 COMPAREITEMSTRUCT *cis = (COMPAREITEMSTRUCT *)msg->lParam;
2244                 HWND ctrl = GetDlgItem(msg->hwnd, cis->CtlID);
2245                 BOOL is_unicode_data = TRUE;
2246 
2247                 ok(msg->wParam == cis->CtlID, "expected %#x, got %#lx\n", cis->CtlID, msg->wParam);
2248                 ok(cis->hwndItem == ctrl, "expected %p, got %p\n", ctrl, cis->hwndItem);
2249                 ok((int)cis->itemID1 >= 0, "expected >= 0, got %d\n", cis->itemID1);
2250                 ok((int)cis->itemID2 == -1, "expected -1, got %d\n", cis->itemID2);
2251 
2252                 sprintf( seq->output, "%s: %p WM_COMPAREITEM: CtlType %#x, CtlID %#x, itemID1 %#x, itemData1 %#lx, itemID2 %#x, itemData2 %#lx",
2253                          msg->descr, msg->hwnd, cis->CtlType, cis->CtlID,
2254                          cis->itemID1, cis->itemData1, cis->itemID2, cis->itemData2);
2255 
2256                 if (cis->CtlType == ODT_LISTBOX)
2257                     is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS;
2258 
2259                 if (is_unicode_data)
2260                 {
2261                     seq->wParam = cis->itemData1 ? hash_Ly_W((const WCHAR *)cis->itemData1) : 0;
2262                     seq->lParam = cis->itemData2 ? hash_Ly_W((const WCHAR *)cis->itemData2) : 0;
2263                 }
2264                 else
2265                 {
2266                     seq->wParam = cis->itemData1 ? hash_Ly((const char *)cis->itemData1) : 0;
2267                     seq->lParam = cis->itemData2 ? hash_Ly((const char *)cis->itemData2) : 0;
2268                 }
2269                 break;
2270             }
2271 
2272             default:
2273                 if (msg->message >= 0xc000) return;  /* ignore registered messages */
2274                 sprintf( seq->output, "%s: %p %04x wp %08lx lp %08lx",
2275                          msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
2276             }
2277             if (msg->flags & (sent|posted|parent|defwinproc|beginpaint))
2278                 sprintf( seq->output + strlen(seq->output), " (flags %x)", msg->flags );
2279         }
2280     }
2281 }
2282 
2283 /* try to make sure pending X events have been processed before continuing */
2284 static void flush_events(void)
2285 {
2286     MSG msg;
2287     int diff = 200;
2288     int min_timeout = 100;
2289     DWORD time = GetTickCount() + diff;
2290 
2291     while (diff > 0)
2292     {
2293         if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
2294         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
2295         diff = time - GetTickCount();
2296     }
2297 }
2298 
2299 static void flush_sequence(void)
2300 {
2301     EnterCriticalSection( &sequence_cs );
2302     HeapFree(GetProcessHeap(), 0, sequence);
2303     sequence = 0;
2304     sequence_cnt = sequence_size = 0;
2305     LeaveCriticalSection( &sequence_cs );
2306 }
2307 
2308 static void dump_sequence(const struct message *expected, const char *context, const char *file, int line)
2309 {
2310     const struct recvd_message *actual = sequence;
2311     unsigned int count = 0;
2312 
2313     trace_(file, line)("Failed sequence %s:\n", context );
2314     while (expected->message && actual->message)
2315     {
2316         if (actual->output[0])
2317         {
2318             if (expected->flags & hook)
2319             {
2320                 trace_(file, line)( "  %u: expected: hook %04x - actual: %s\n",
2321                                     count, expected->message, actual->output );
2322             }
2323             else if (expected->flags & winevent_hook)
2324             {
2325                 trace_(file, line)( "  %u: expected: winevent %04x - actual: %s\n",
2326                                     count, expected->message, actual->output );
2327             }
2328             else if (expected->flags & kbd_hook)
2329             {
2330                 trace_(file, line)( "  %u: expected: kbd %04x - actual: %s\n",
2331                                     count, expected->message, actual->output );
2332             }
2333             else
2334             {
2335                 trace_(file, line)( "  %u: expected: msg %04x - actual: %s\n",
2336                                     count, expected->message, actual->output );
2337             }
2338         }
2339 
2340 	if (expected->message == actual->message)
2341 	{
2342 	    if ((expected->flags & defwinproc) != (actual->flags & defwinproc) &&
2343                 (expected->flags & optional))
2344             {
2345                 /* don't match messages if their defwinproc status differs */
2346                 expected++;
2347             }
2348             else
2349             {
2350                 expected++;
2351                 actual++;
2352             }
2353 	}
2354 	/* silently drop winevent messages if there is no support for them */
2355 	else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
2356 	    expected++;
2357         else
2358         {
2359             expected++;
2360             actual++;
2361         }
2362         count++;
2363     }
2364 
2365     /* optional trailing messages */
2366     while (expected->message && ((expected->flags & optional) ||
2367 	    ((expected->flags & winevent_hook) && !hEvent_hook)))
2368     {
2369         trace_(file, line)( "  %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2370 	expected++;
2371         count++;
2372     }
2373 
2374     if (expected->message)
2375     {
2376         trace_(file, line)( "  %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2377         return;
2378     }
2379 
2380     while (actual->message && actual->output[0])
2381     {
2382         trace_(file, line)( "  %u: expected: nothing - actual: %s\n", count, actual->output );
2383         actual++;
2384         count++;
2385     }
2386 }
2387 
2388 #define ok_sequence( exp, contx, todo) \
2389         ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
2390 
2391 
2392 static void ok_sequence_(const struct message *expected_list, const char *context, BOOL todo,
2393                          const char *file, int line)
2394 {
2395     static const struct recvd_message end_of_sequence;
2396     const struct message *expected = expected_list;
2397     const struct recvd_message *actual;
2398     int failcount = 0, dump = 0;
2399     unsigned int count = 0;
2400 
2401     add_message(&end_of_sequence);
2402 
2403     actual = sequence;
2404 
2405     while (expected->message && actual->message)
2406     {
2407 	if (expected->message == actual->message &&
2408             !((expected->flags ^ actual->flags) & (hook|winevent_hook|kbd_hook)))
2409 	{
2410 	    if (expected->flags & wparam)
2411 	    {
2412 		if (((expected->wParam ^ actual->wParam) & ~expected->wp_mask) && todo)
2413 		{
2414 		    todo_wine {
2415                         failcount ++;
2416                         if (strcmp(winetest_platform, "wine")) dump++;
2417                         ok_( file, line) (FALSE,
2418 			    "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2419                             context, count, expected->message, expected->wParam, actual->wParam);
2420 		    }
2421 		}
2422 		else
2423                 {
2424                     ok_( file, line)( ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) == 0,
2425                                      "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2426                                      context, count, expected->message, expected->wParam, actual->wParam);
2427                     if ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) dump++;
2428                 }
2429 
2430 	    }
2431 	    if (expected->flags & lparam)
2432             {
2433 		if (((expected->lParam ^ actual->lParam) & ~expected->lp_mask) && todo)
2434 		{
2435 		    todo_wine {
2436                         failcount ++;
2437                         if (strcmp(winetest_platform, "wine")) dump++;
2438                         ok_( file, line) (FALSE,
2439 			    "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2440                             context, count, expected->message, expected->lParam, actual->lParam);
2441 		    }
2442 		}
2443 		else
2444                 {
2445                     ok_( file, line)(((expected->lParam ^ actual->lParam) & ~expected->lp_mask) == 0,
2446                                      "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2447                                      context, count, expected->message, expected->lParam, actual->lParam);
2448                     if ((expected->lParam ^ actual->lParam) & ~expected->lp_mask) dump++;
2449                 }
2450             }
2451 	    if ((expected->flags & optional) &&
2452                 ((expected->flags ^ actual->flags) & (defwinproc|parent)))
2453             {
2454                 /* don't match optional messages if their defwinproc or parent status differs */
2455                 expected++;
2456                 count++;
2457                 continue;
2458             }
2459 	    if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
2460 	    {
2461 		    todo_wine {
2462                         failcount ++;
2463                         if (strcmp(winetest_platform, "wine")) dump++;
2464                         ok_( file, line) (FALSE,
2465                             "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2466                             context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2467 		    }
2468 	    }
2469 	    else
2470             {
2471 	        ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
2472 		    "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2473                     context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2474                 if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) dump++;
2475             }
2476 
2477 	    ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
2478 		"%s: %u: the msg 0x%04x should %shave been sent by BeginPaint\n",
2479                 context, count, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
2480             if ((expected->flags & beginpaint) != (actual->flags & beginpaint)) dump++;
2481 
2482 	    ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
2483 		"%s: %u: the msg 0x%04x should have been %s\n",
2484                 context, count, expected->message, (expected->flags & posted) ? "posted" : "sent");
2485             if ((expected->flags & (sent|posted)) != (actual->flags & (sent|posted))) dump++;
2486 
2487 	    ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
2488 		"%s: %u: the msg 0x%04x was expected in %s\n",
2489                 context, count, expected->message, (expected->flags & parent) ? "parent" : "child");
2490             if ((expected->flags & parent) != (actual->flags & parent)) dump++;
2491 
2492 	    ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
2493 		"%s: %u: the msg 0x%04x should have been sent by a hook\n",
2494                 context, count, expected->message);
2495             if ((expected->flags & hook) != (actual->flags & hook)) dump++;
2496 
2497 	    ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
2498 		"%s: %u: the msg 0x%04x should have been sent by a winevent hook\n",
2499                 context, count, expected->message);
2500             if ((expected->flags & winevent_hook) != (actual->flags & winevent_hook)) dump++;
2501 
2502 	    ok_( file, line) ((expected->flags & kbd_hook) == (actual->flags & kbd_hook),
2503 		"%s: %u: the msg 0x%04x should have been sent by a keyboard hook\n",
2504                 context, count, expected->message);
2505             if ((expected->flags & kbd_hook) != (actual->flags & kbd_hook)) dump++;
2506 
2507 	    expected++;
2508 	    actual++;
2509 	}
2510 	/* silently drop hook messages if there is no support for them */
2511 	else if ((expected->flags & optional) ||
2512                  ((expected->flags & hook) && !hCBT_hook) ||
2513                  ((expected->flags & winevent_hook) && !hEvent_hook) ||
2514                  ((expected->flags & kbd_hook) && !hKBD_hook))
2515 	    expected++;
2516 	else if (todo)
2517 	{
2518             failcount++;
2519             todo_wine {
2520                 if (strcmp(winetest_platform, "wine")) dump++;
2521                 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2522                                   context, count, expected->message, actual->message);
2523             }
2524             goto done;
2525         }
2526         else
2527         {
2528             ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2529                               context, count, expected->message, actual->message);
2530             dump++;
2531             expected++;
2532             actual++;
2533         }
2534         count++;
2535     }
2536 
2537     /* skip all optional trailing messages */
2538     while (expected->message && ((expected->flags & optional) ||
2539                                  ((expected->flags & hook) && !hCBT_hook) ||
2540                                  ((expected->flags & winevent_hook) && !hEvent_hook)))
2541 	expected++;
2542 
2543     if (todo)
2544     {
2545         todo_wine {
2546             if (expected->message || actual->message) {
2547                 failcount++;
2548                 if (strcmp(winetest_platform, "wine")) dump++;
2549                 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2550                                   context, count, expected->message, actual->message);
2551             }
2552         }
2553     }
2554     else
2555     {
2556         if (expected->message || actual->message)
2557         {
2558             dump++;
2559             ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2560                               context, count, expected->message, actual->message);
2561         }
2562     }
2563     if( todo && !failcount) /* succeeded yet marked todo */
2564         todo_wine {
2565             if (!strcmp(winetest_platform, "wine")) dump++;
2566             ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
2567         }
2568 
2569 done:
2570     if (dump) dump_sequence(expected_list, context, file, line);
2571     flush_sequence();
2572 }
2573 
2574 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT))
2575 
2576 /******************************** MDI test **********************************/
2577 
2578 /* CreateWindow for MDI frame window, initially visible */
2579 static const struct message WmCreateMDIframeSeq[] = {
2580     { HCBT_CREATEWND, hook },
2581     { WM_GETMINMAXINFO, sent },
2582     { WM_NCCREATE, sent },
2583     { WM_NCCALCSIZE, sent|wparam, 0 },
2584     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2585     { WM_CREATE, sent },
2586     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2587     { WM_NOTIFYFORMAT, sent|optional },
2588     { WM_QUERYUISTATE, sent|optional },
2589     { WM_WINDOWPOSCHANGING, sent|optional },
2590     { WM_GETMINMAXINFO, sent|optional },
2591     { WM_NCCALCSIZE, sent|optional },
2592     { WM_WINDOWPOSCHANGED, sent|optional },
2593     { WM_SHOWWINDOW, sent|wparam, 1 },
2594     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2595     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2596     { HCBT_ACTIVATE, hook },
2597     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
2598     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
2599     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
2600     { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
2601     { WM_NCACTIVATE, sent },
2602     { WM_GETTEXT, sent|defwinproc|optional },
2603     { WM_ACTIVATE, sent|wparam, 1 },
2604     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
2605     { HCBT_SETFOCUS, hook },
2606     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2607     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2608     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2609     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
2610     /* Win9x adds SWP_NOZORDER below */
2611     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2612     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2613     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2614     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2615     { WM_MOVE, sent },
2616     { 0 }
2617 };
2618 /* DestroyWindow for MDI frame window, initially visible */
2619 static const struct message WmDestroyMDIframeSeq[] = {
2620     { HCBT_DESTROYWND, hook },
2621     { 0x0090, sent|optional },
2622     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2623     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2624     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2625     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2626     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
2627     { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2628     { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
2629     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
2630     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2631     { WM_DESTROY, sent },
2632     { WM_NCDESTROY, sent },
2633     { 0 }
2634 };
2635 /* CreateWindow for MDI client window, initially visible */
2636 static const struct message WmCreateMDIclientSeq[] = {
2637     { HCBT_CREATEWND, hook },
2638     { WM_NCCREATE, sent },
2639     { WM_NCCALCSIZE, sent|wparam, 0 },
2640     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2641     { WM_CREATE, sent },
2642     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2643     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2644     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2645     { WM_MOVE, sent },
2646     { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
2647     { WM_SHOWWINDOW, sent|wparam, 1 },
2648     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2649     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2650     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2651     { 0 }
2652 };
2653 /* ShowWindow(SW_SHOW) for MDI client window */
2654 static const struct message WmShowMDIclientSeq[] = {
2655     { WM_SHOWWINDOW, sent|wparam, 1 },
2656     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2657     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2658     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2659     { 0 }
2660 };
2661 /* ShowWindow(SW_HIDE) for MDI client window */
2662 static const struct message WmHideMDIclientSeq[] = {
2663     { WM_SHOWWINDOW, sent|wparam, 0 },
2664     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2665     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
2666     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
2667     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2668     { 0 }
2669 };
2670 /* DestroyWindow for MDI client window, initially visible */
2671 static const struct message WmDestroyMDIclientSeq[] = {
2672     { HCBT_DESTROYWND, hook },
2673     { 0x0090, sent|optional },
2674     { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
2675     { WM_SHOWWINDOW, sent|wparam, 0 },
2676     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2677     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2678     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2679     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2680     { WM_DESTROY, sent },
2681     { WM_NCDESTROY, sent },
2682     { 0 }
2683 };
2684 /* CreateWindow for MDI child window, initially visible */
2685 static const struct message WmCreateMDIchildVisibleSeq[] = {
2686     { HCBT_CREATEWND, hook },
2687     { WM_NCCREATE, sent },
2688     { WM_NCCALCSIZE, sent|wparam, 0 },
2689     { WM_CREATE, sent },
2690     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2691     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2692     { WM_MOVE, sent },
2693     /* Win2k sends wparam set to
2694      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2695      * while Win9x doesn't bother to set child window id according to
2696      * CLIENTCREATESTRUCT.idFirstChild
2697      */
2698     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2699     { WM_SHOWWINDOW, sent|wparam, 1 },
2700     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2701     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2702     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2703     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2704     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2705     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2706     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2707 
2708     /* Win9x: message sequence terminates here. */
2709 
2710     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2711     { HCBT_SETFOCUS, hook }, /* in MDI client */
2712     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2713     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2714     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2715     { WM_SETFOCUS, sent }, /* in MDI client */
2716     { HCBT_SETFOCUS, hook },
2717     { WM_KILLFOCUS, sent }, /* in MDI client */
2718     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2719     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2720     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2721     { WM_SETFOCUS, sent|defwinproc },
2722     { WM_MDIACTIVATE, sent|defwinproc },
2723     { 0 }
2724 };
2725 /* WM_CHILDACTIVATE sent to disabled window */
2726 static const struct message WmChildActivateDisabledWindowSeq[] = {
2727     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2728     { 0 }
2729 };
2730 /* WM_CHILDACTIVATE sent to enabled window */
2731 static const struct message WmChildActivateWindowSeq[] = {
2732     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2733     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 },
2734     { WM_MDIACTIVATE, sent|defwinproc },
2735     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2736     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2737     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2738     { HCBT_SETFOCUS, hook },
2739     { WM_KILLFOCUS, sent|defwinproc },
2740     { WM_SETFOCUS, sent },
2741     { HCBT_SETFOCUS, hook },
2742     { WM_KILLFOCUS, sent },
2743     { WM_SETFOCUS, sent|defwinproc },
2744     { WM_MDIACTIVATE, sent|defwinproc },
2745     { 0 }
2746 };
2747 /* CreateWindow for MDI child window with invisible parent */
2748 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
2749     { HCBT_CREATEWND, hook },
2750     { WM_GETMINMAXINFO, sent },
2751     { WM_NCCREATE, sent },
2752     { WM_NCCALCSIZE, sent|wparam, 0 },
2753     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2754     { WM_CREATE, sent },
2755     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2756     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2757     { WM_MOVE, sent },
2758     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2759     { WM_SHOWWINDOW, sent|wparam, 1 },
2760     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2761     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2762     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2763     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2764 
2765     /* Win9x: message sequence terminates here. */
2766 
2767     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2768     { HCBT_SETFOCUS, hook }, /* in MDI client */
2769     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2770     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2771     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2772     { WM_SETFOCUS, sent }, /* in MDI client */
2773     { HCBT_SETFOCUS, hook },
2774     { WM_KILLFOCUS, sent }, /* in MDI client */
2775     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2776     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2777     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2778     { WM_SETFOCUS, sent|defwinproc },
2779     { WM_MDIACTIVATE, sent|defwinproc },
2780     { 0 }
2781 };
2782 /* DestroyWindow for MDI child window, initially visible */
2783 static const struct message WmDestroyMDIchildVisibleSeq[] = {
2784     { HCBT_DESTROYWND, hook },
2785     /* Win2k sends wparam set to
2786      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2787      * while Win9x doesn't bother to set child window id according to
2788      * CLIENTCREATESTRUCT.idFirstChild
2789      */
2790     { 0x0090, sent|optional },
2791     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2792     { WM_SHOWWINDOW, sent|wparam, 0 },
2793     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2794     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2795     { WM_ERASEBKGND, sent|parent|optional },
2796     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2797 
2798     /* { WM_DESTROY, sent }
2799      * Win9x: message sequence terminates here.
2800      */
2801 
2802     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2803     { WM_KILLFOCUS, sent },
2804     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2805     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2806     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2807     { WM_SETFOCUS, sent }, /* in MDI client */
2808 
2809     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2810     { WM_KILLFOCUS, sent }, /* in MDI client */
2811     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2812     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2813     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2814     { WM_SETFOCUS, sent }, /* in MDI client */
2815 
2816     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2817 
2818     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2819     { WM_KILLFOCUS, sent },
2820     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2821     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2822     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2823     { WM_SETFOCUS, sent }, /* in MDI client */
2824 
2825     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2826     { WM_KILLFOCUS, sent }, /* in MDI client */
2827     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2828     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2829     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2830     { WM_SETFOCUS, sent }, /* in MDI client */
2831 
2832     { WM_DESTROY, sent },
2833 
2834     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2835     { WM_KILLFOCUS, sent },
2836     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2837     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2838     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2839     { WM_SETFOCUS, sent }, /* in MDI client */
2840 
2841     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2842     { WM_KILLFOCUS, sent }, /* in MDI client */
2843     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2844     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2845     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2846     { WM_SETFOCUS, sent }, /* in MDI client */
2847 
2848     { WM_NCDESTROY, sent },
2849     { 0 }
2850 };
2851 /* CreateWindow for MDI child window, initially invisible */
2852 static const struct message WmCreateMDIchildInvisibleSeq[] = {
2853     { HCBT_CREATEWND, hook },
2854     { WM_NCCREATE, sent },
2855     { WM_NCCALCSIZE, sent|wparam, 0 },
2856     { WM_CREATE, sent },
2857     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2858     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2859     { WM_MOVE, sent },
2860     /* Win2k sends wparam set to
2861      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2862      * while Win9x doesn't bother to set child window id according to
2863      * CLIENTCREATESTRUCT.idFirstChild
2864      */
2865     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2866     { 0 }
2867 };
2868 /* DestroyWindow for MDI child window, initially invisible */
2869 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
2870     { HCBT_DESTROYWND, hook },
2871     /* Win2k sends wparam set to
2872      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2873      * while Win9x doesn't bother to set child window id according to
2874      * CLIENTCREATESTRUCT.idFirstChild
2875      */
2876     { 0x0090, sent|optional },
2877     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2878     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2879     { WM_DESTROY, sent },
2880     { WM_NCDESTROY, sent },
2881     /* FIXME: Wine destroys an icon/title window while Windows doesn't */
2882     { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */
2883     { 0 }
2884 };
2885 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
2886 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
2887     { HCBT_CREATEWND, hook },
2888     { WM_NCCREATE, sent },
2889     { WM_NCCALCSIZE, sent|wparam, 0 },
2890     { WM_CREATE, sent },
2891     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2892     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2893     { WM_MOVE, sent },
2894     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2895     { WM_GETMINMAXINFO, sent },
2896     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED  },
2897     { WM_NCCALCSIZE, sent|wparam, 1 },
2898     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2899     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2900      /* in MDI frame */
2901     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2902     { WM_NCCALCSIZE, sent|wparam, 1 },
2903     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2904     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2905     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2906     /* Win2k sends wparam set to
2907      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2908      * while Win9x doesn't bother to set child window id according to
2909      * CLIENTCREATESTRUCT.idFirstChild
2910      */
2911     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2912     { WM_SHOWWINDOW, sent|wparam, 1 },
2913     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2914     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2915     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2916     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2917     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2918     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2919     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_FRAMECHANGED },
2920 
2921     /* Win9x: message sequence terminates here. */
2922 
2923     { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
2924     { HCBT_SETFOCUS, hook|optional }, /* in MDI client */
2925     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2926     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2927     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2928     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2929     { HCBT_SETFOCUS, hook|optional },
2930     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
2931     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2932     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2933     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2934     { WM_SETFOCUS, sent|defwinproc|optional },
2935     { WM_MDIACTIVATE, sent|defwinproc|optional },
2936      /* in MDI frame */
2937     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2938     { WM_NCCALCSIZE, sent|wparam, 1 },
2939     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2940     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2941     { 0 }
2942 };
2943 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
2944 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
2945     /* restore the 1st MDI child */
2946     { WM_SETREDRAW, sent|wparam, 0 },
2947     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2948     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2949     { WM_NCCALCSIZE, sent|wparam, 1 },
2950     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2951     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2952     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2953      /* in MDI frame */
2954     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2955     { WM_NCCALCSIZE, sent|wparam, 1 },
2956     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2957     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2958     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2959     { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
2960     /* create the 2nd MDI child */
2961     { HCBT_CREATEWND, hook },
2962     { WM_NCCREATE, sent },
2963     { WM_NCCALCSIZE, sent|wparam, 0 },
2964     { WM_CREATE, sent },
2965     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2966     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2967     { WM_MOVE, sent },
2968     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2969     { WM_GETMINMAXINFO, sent },
2970     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2971     { WM_NCCALCSIZE, sent|wparam, 1 },
2972     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2973     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2974     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2975      /* in MDI frame */
2976     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2977     { WM_NCCALCSIZE, sent|wparam, 1 },
2978     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2979     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2980     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2981     /* Win2k sends wparam set to
2982      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2983      * while Win9x doesn't bother to set child window id according to
2984      * CLIENTCREATESTRUCT.idFirstChild
2985      */
2986     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2987     { WM_SHOWWINDOW, sent|wparam, 1 },
2988     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2989     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2990     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2991     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2992     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2993     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2994 
2995     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2996     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2997 
2998     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2999 
3000     /* Win9x: message sequence terminates here. */
3001 
3002     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3003     { HCBT_SETFOCUS, hook },
3004     { WM_KILLFOCUS, sent|defwinproc|optional }, /* in the 1st MDI child */
3005     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
3006     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3007     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3008     { WM_SETFOCUS, sent }, /* in MDI client */
3009     { HCBT_SETFOCUS, hook },
3010     { WM_KILLFOCUS, sent }, /* in MDI client */
3011     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3012     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3013     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3014     { WM_SETFOCUS, sent|defwinproc },
3015 
3016     { WM_MDIACTIVATE, sent|defwinproc },
3017      /* in MDI frame */
3018     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3019     { WM_NCCALCSIZE, sent|wparam, 1 },
3020     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3021     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3022     { 0 }
3023 };
3024 /* WM_MDICREATE MDI child window, initially visible and maximized */
3025 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
3026     { WM_MDICREATE, sent },
3027     { HCBT_CREATEWND, hook },
3028     { WM_NCCREATE, sent },
3029     { WM_NCCALCSIZE, sent|wparam, 0 },
3030     { WM_CREATE, sent },
3031     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3032     { WM_SIZE, sent|wparam, SIZE_RESTORED },
3033     { WM_MOVE, sent },
3034     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3035     { WM_GETMINMAXINFO, sent },
3036     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3037     { WM_NCCALCSIZE, sent|wparam, 1 },
3038     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3039     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3040 
3041      /* in MDI frame */
3042     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3043     { WM_NCCALCSIZE, sent|wparam, 1 },
3044     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3045     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3046     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3047 
3048     /* Win2k sends wparam set to
3049      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3050      * while Win9x doesn't bother to set child window id according to
3051      * CLIENTCREATESTRUCT.idFirstChild
3052      */
3053     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3054     { WM_SHOWWINDOW, sent|wparam, 1 },
3055     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3056 
3057     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3058 
3059     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3060     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
3061     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
3062 
3063     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3064     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3065 
3066     /* Win9x: message sequence terminates here. */
3067 
3068     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3069     { WM_SETFOCUS, sent|optional }, /* in MDI client */
3070     { HCBT_SETFOCUS, hook }, /* in MDI client */
3071     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3072     { WM_IME_NOTIFY, sent|wparam|optional, 2 },
3073     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
3074     { WM_SETFOCUS, sent|optional }, /* in MDI client */
3075     { HCBT_SETFOCUS, hook|optional },
3076     { WM_KILLFOCUS, sent }, /* in MDI client */
3077     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3078     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3079     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3080     { WM_SETFOCUS, sent|defwinproc },
3081 
3082     { WM_MDIACTIVATE, sent|defwinproc },
3083 
3084      /* in MDI child */
3085     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3086     { WM_NCCALCSIZE, sent|wparam, 1 },
3087     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3088     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
3089 
3090      /* in MDI frame */
3091     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3092     { WM_NCCALCSIZE, sent|wparam, 1 },
3093     { 0x0093, sent|defwinproc|optional },
3094     { 0x0093, sent|defwinproc|optional },
3095     { 0x0093, sent|defwinproc|optional },
3096     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3097     { WM_MOVE, sent|defwinproc },
3098     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3099 
3100      /* in MDI client */
3101     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3102     { WM_NCCALCSIZE, sent|wparam, 1 },
3103     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3104     { WM_SIZE, sent|wparam, SIZE_RESTORED },
3105 
3106      /* in MDI child */
3107     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3108     { WM_NCCALCSIZE, sent|wparam, 1 },
3109     { 0x0093, sent|optional },
3110     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3111     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3112 
3113     { 0x0093, sent|optional },
3114     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3115     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3116     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
3117     { 0x0093, sent|defwinproc|optional },
3118     { 0x0093, sent|defwinproc|optional },
3119     { 0x0093, sent|defwinproc|optional },
3120     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3121     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3122 
3123     { 0 }
3124 };
3125 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
3126 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
3127     { HCBT_CREATEWND, hook },
3128     { WM_GETMINMAXINFO, sent },
3129     { WM_NCCREATE, sent },
3130     { WM_NCCALCSIZE, sent|wparam, 0 },
3131     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
3132     { WM_CREATE, sent },
3133     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3134     { WM_SIZE, sent|wparam, SIZE_RESTORED },
3135     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOZORDER }, /* MDI frame */
3136     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI frame */
3137     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOZORDER }, /* MDI frame */
3138     { WM_MOVE, sent },
3139     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3140     { WM_GETMINMAXINFO, sent },
3141     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3142     { WM_GETMINMAXINFO, sent|defwinproc },
3143     { WM_NCCALCSIZE, sent|wparam, 1 },
3144     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_STATECHANGED },
3145     { WM_MOVE, sent|defwinproc },
3146     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3147      /* in MDI frame */
3148     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3149     { WM_NCCALCSIZE, sent|wparam, 1 },
3150     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3151     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3152     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
3153     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3154     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3155     /* Win2k sends wparam set to
3156      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3157      * while Win9x doesn't bother to set child window id according to
3158      * CLIENTCREATESTRUCT.idFirstChild
3159      */
3160     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3161     { 0 }
3162 };
3163 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
3164 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
3165     { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
3166     { HCBT_SYSCOMMAND, hook },
3167     { WM_CLOSE, sent|defwinproc },
3168     { WM_MDIDESTROY, sent }, /* in MDI client */
3169 
3170     /* bring the 1st MDI child to top */
3171     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
3172     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
3173 
3174     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3175 
3176     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
3177     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
3178     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
3179 
3180     /* maximize the 1st MDI child */
3181     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3182     { WM_GETMINMAXINFO, sent|defwinproc },
3183     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED },
3184     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
3185     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
3186     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3187     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3188 
3189     /* restore the 2nd MDI child */
3190     { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
3191     { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
3192     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
3193     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
3194 
3195     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3196 
3197     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3198     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3199 
3200     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3201 
3202     { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
3203      /* in MDI frame */
3204     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3205     { WM_NCCALCSIZE, sent|wparam, 1 },
3206     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3207     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3208     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3209 
3210     /* bring the 1st MDI child to top */
3211     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3212     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3213     { HCBT_SETFOCUS, hook },
3214     { WM_KILLFOCUS, sent|defwinproc },
3215     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
3216     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3217     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3218     { WM_SETFOCUS, sent }, /* in MDI client */
3219     { HCBT_SETFOCUS, hook },
3220     { WM_KILLFOCUS, sent }, /* in MDI client */
3221     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3222     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3223     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3224     { WM_SETFOCUS, sent|defwinproc },
3225     { WM_MDIACTIVATE, sent|defwinproc },
3226     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3227 
3228     /* apparently ShowWindow(SW_SHOW) on an MDI client */
3229     { WM_SHOWWINDOW, sent|wparam, 1 },
3230     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3231     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3232     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3233     { WM_MDIREFRESHMENU, sent },
3234 
3235     { HCBT_DESTROYWND, hook },
3236     /* Win2k sends wparam set to
3237      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3238      * while Win9x doesn't bother to set child window id according to
3239      * CLIENTCREATESTRUCT.idFirstChild
3240      */
3241     { 0x0090, sent|defwinproc|optional },
3242     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3243     { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
3244     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3245     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3246     { WM_ERASEBKGND, sent|parent|optional },
3247     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3248 
3249     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
3250     { WM_DESTROY, sent|defwinproc },
3251     { WM_NCDESTROY, sent|defwinproc },
3252     { 0 }
3253 };
3254 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
3255 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
3256     { WM_MDIDESTROY, sent }, /* in MDI client */
3257     { WM_SHOWWINDOW, sent|wparam, 0 },
3258     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3259     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3260     { WM_ERASEBKGND, sent|parent|optional },
3261     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3262 
3263     { HCBT_SETFOCUS, hook },
3264     { WM_KILLFOCUS, sent },
3265     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3266     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3267     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3268     { WM_SETFOCUS, sent }, /* in MDI client */
3269     { HCBT_SETFOCUS, hook },
3270     { WM_KILLFOCUS, sent }, /* in MDI client */
3271     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3272     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3273     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3274     { WM_SETFOCUS, sent },
3275 
3276      /* in MDI child */
3277     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3278     { WM_NCCALCSIZE, sent|wparam, 1 },
3279     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3280     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3281 
3282      /* in MDI frame */
3283     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3284     { WM_NCCALCSIZE, sent|wparam, 1 },
3285     { 0x0093, sent|defwinproc|optional },
3286     { 0x0093, sent|defwinproc|optional },
3287     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3288     { WM_MOVE, sent|defwinproc },
3289     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3290 
3291      /* in MDI client */
3292     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3293     { WM_NCCALCSIZE, sent|wparam, 1 },
3294     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3295     { WM_SIZE, sent|wparam, SIZE_RESTORED },
3296 
3297      /* in MDI child */
3298     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3299     { WM_NCCALCSIZE, sent|wparam, 1 },
3300     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3301     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3302 
3303      /* in MDI child */
3304     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3305     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3306     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3307     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3308 
3309      /* in MDI frame */
3310     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3311     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3312     { 0x0093, sent|defwinproc|optional },
3313     { 0x0093, sent|defwinproc|optional },
3314     { 0x0093, sent|defwinproc|optional },
3315     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3316     { WM_MOVE, sent|defwinproc },
3317     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3318 
3319      /* in MDI client */
3320     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3321     { WM_NCCALCSIZE, sent|wparam, 1 },
3322     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3323     { WM_SIZE, sent|wparam, SIZE_RESTORED },
3324 
3325      /* in MDI child */
3326     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3327     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3328     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3329     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3330     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3331     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3332 
3333     { 0x0093, sent|defwinproc|optional },
3334     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
3335     { 0x0093, sent|defwinproc|optional },
3336     { 0x0093, sent|defwinproc|optional },
3337     { 0x0093, sent|defwinproc|optional },
3338     { 0x0093, sent|optional },
3339 
3340     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3341     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3342     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3343     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3344     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3345 
3346      /* in MDI frame */
3347     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3348     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3349     { 0x0093, sent|defwinproc|optional },
3350     { 0x0093, sent|defwinproc|optional },
3351     { 0x0093, sent|defwinproc|optional },
3352     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3353     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3354     { 0x0093, sent|optional },
3355 
3356     { WM_NCACTIVATE, sent|wparam, 0 },
3357     { WM_MDIACTIVATE, sent },
3358 
3359     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
3360     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
3361     { WM_NCCALCSIZE, sent|wparam, 1 },
3362 
3363     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3364 
3365     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3366     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3367     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3368 
3369      /* in MDI child */
3370     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3371     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3372     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3373     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3374 
3375      /* in MDI frame */
3376     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3377     { WM_NCCALCSIZE, sent|wparam, 1 },
3378     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3379     { WM_MOVE, sent|defwinproc },
3380     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3381 
3382      /* in MDI client */
3383     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3384     { WM_NCCALCSIZE, sent|wparam, 1 },
3385     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3386     { WM_SIZE, sent|wparam, SIZE_RESTORED },
3387     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3388     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
3389     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3390     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3391     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3392 
3393     { HCBT_SETFOCUS, hook },
3394     { WM_KILLFOCUS, sent },
3395     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3396     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3397     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3398     { WM_SETFOCUS, sent }, /* in MDI client */
3399 
3400     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
3401 
3402     { HCBT_DESTROYWND, hook },
3403     /* Win2k sends wparam set to
3404      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3405      * while Win9x doesn't bother to set child window id according to
3406      * CLIENTCREATESTRUCT.idFirstChild
3407      */
3408     { 0x0090, sent|optional },
3409     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3410 
3411     { WM_SHOWWINDOW, sent|wparam, 0 },
3412     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3413     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3414     { WM_ERASEBKGND, sent|parent|optional },
3415     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3416 
3417     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
3418     { WM_DESTROY, sent },
3419     { WM_NCDESTROY, sent },
3420     { 0 }
3421 };
3422 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
3423 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
3424     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3425     { WM_GETMINMAXINFO, sent },
3426     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3427     { WM_NCCALCSIZE, sent|wparam, 1 },
3428     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3429     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3430 
3431     { WM_WINDOWPOSCHANGING, sent|wparam|optional|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3432     { WM_NCACTIVATE, sent|wparam|optional|defwinproc, 1 },
3433     { HCBT_SETFOCUS, hook|optional },
3434     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3435     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3436     { WM_SETFOCUS, sent|optional }, /* in MDI client */
3437     { HCBT_SETFOCUS, hook|optional },
3438     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3439     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3440     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3441     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3442     { WM_SETFOCUS, sent|optional|defwinproc },
3443     { WM_MDIACTIVATE, sent|optional|defwinproc },
3444     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3445     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3446      /* in MDI frame */
3447     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3448     { WM_NCCALCSIZE, sent|wparam, 1 },
3449     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3450     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3451     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3452     { 0 }
3453 };
3454 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
3455 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
3456     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3457     { WM_GETMINMAXINFO, sent },
3458     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
3459     { WM_GETMINMAXINFO, sent|defwinproc },
3460     { WM_NCCALCSIZE, sent|wparam, 1 },
3461     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3462     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3463 
3464     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3465     { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
3466     { HCBT_SETFOCUS, hook|optional },
3467     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3468     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3469     { WM_SETFOCUS, sent|optional }, /* in MDI client */
3470     { HCBT_SETFOCUS, hook|optional },
3471     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3472     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3473     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3474     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3475     { WM_SETFOCUS, sent|defwinproc|optional },
3476     { WM_MDIACTIVATE, sent|defwinproc|optional },
3477     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3478     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3479     { WM_SIZE, sent|defwinproc|optional },
3480     { 0 }
3481 };
3482 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
3483 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
3484     { WM_MDIMAXIMIZE, sent }, /* in MDI client */
3485     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3486     { WM_GETMINMAXINFO, sent },
3487     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3488     { WM_GETMINMAXINFO, sent|defwinproc },
3489     { WM_NCCALCSIZE, sent|wparam, 1 },
3490     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
3491     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3492     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
3493     { WM_MOVE, sent|defwinproc },
3494     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3495 
3496     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3497     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3498     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3499     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3500     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3501     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3502      /* in MDI frame */
3503     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3504     { WM_NCCALCSIZE, sent|wparam, 1 },
3505     { 0x0093, sent|defwinproc|optional },
3506     { 0x0094, sent|defwinproc|optional },
3507     { 0x0094, sent|defwinproc|optional },
3508     { 0x0094, sent|defwinproc|optional },
3509     { 0x0094, sent|defwinproc|optional },
3510     { 0x0093, sent|defwinproc|optional },
3511     { 0x0093, sent|defwinproc|optional },
3512     { 0x0091, sent|defwinproc|optional },
3513     { 0x0092, sent|defwinproc|optional },
3514     { 0x0092, sent|defwinproc|optional },
3515     { 0x0092, sent|defwinproc|optional },
3516     { 0x0092, sent|defwinproc|optional },
3517     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3518     { WM_MOVE, sent|defwinproc },
3519     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3520     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
3521      /* in MDI client */
3522     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3523     { WM_NCCALCSIZE, sent|wparam, 1 },
3524     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3525     { WM_SIZE, sent|wparam, SIZE_RESTORED },
3526      /* in MDI child */
3527     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3528     { WM_GETMINMAXINFO, sent|defwinproc },
3529     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3530     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3531     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3532     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
3533     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3534     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3535     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3536     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3537      /* in MDI frame */
3538     { 0x0093, sent|optional },
3539     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3540     { 0x0093, sent|defwinproc|optional },
3541     { 0x0093, sent|defwinproc|optional },
3542     { 0x0093, sent|defwinproc|optional },
3543     { 0x0091, sent|defwinproc|optional },
3544     { 0x0092, sent|defwinproc|optional },
3545     { 0x0092, sent|defwinproc|optional },
3546     { 0x0092, sent|defwinproc|optional },
3547     { 0x0092, sent|defwinproc|optional },
3548     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3549     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3550     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3551     { 0 }
3552 };
3553 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
3554 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
3555     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3556     { WM_GETMINMAXINFO, sent },
3557     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3558     { WM_NCCALCSIZE, sent|wparam, 1 },
3559     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3560     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3561     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3562      /* in MDI frame */
3563     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3564     { WM_NCCALCSIZE, sent|wparam, 1 },
3565     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3566     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3567     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3568     { 0 }
3569 };
3570 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
3571 static const struct message WmRestoreMDIchildVisibleSeq[] = {
3572     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3573     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3574     { WM_NCCALCSIZE, sent|wparam, 1 },
3575     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3576     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3577     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3578      /* in MDI frame */
3579     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3580     { WM_NCCALCSIZE, sent|wparam, 1 },
3581     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3582     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3583     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3584     { 0 }
3585 };
3586 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
3587 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
3588     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3589     { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
3590     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3591     { WM_NCCALCSIZE, sent|wparam, 1 },
3592     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3593     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3594     { WM_MOVE, sent|defwinproc },
3595     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3596     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3597     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3598     { HCBT_SETFOCUS, hook },
3599     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3600     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
3601     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3602     { WM_SETFOCUS, sent },
3603     { 0 }
3604 };
3605 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
3606 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
3607     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
3608     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3609     { WM_NCCALCSIZE, sent|wparam, 1 },
3610     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3611     { WM_MOVE, sent|defwinproc },
3612     { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
3613     { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
3614     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3615     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3616     /* FIXME: Wine creates an icon/title window while Windows doesn't */
3617     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */
3618     { 0 }
3619 };
3620 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
3621 static const struct message WmRestoreMDIchildInvisibleSeq[] = {
3622     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3623     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED  },
3624     { WM_NCCALCSIZE, sent|wparam, 1 },
3625     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3626     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3627     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3628     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3629      /* in MDI frame */
3630     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3631     { WM_NCCALCSIZE, sent|wparam, 1 },
3632     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3633     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3634     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3635     { 0 }
3636 };
3637 
3638 static HWND mdi_client;
3639 static WNDPROC old_mdi_client_proc;
3640 
3641 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3642 {
3643     struct recvd_message msg;
3644 
3645     /* do not log painting messages */
3646     if (message != WM_PAINT &&
3647         message != WM_NCPAINT &&
3648         message != WM_SYNCPAINT &&
3649         message != WM_ERASEBKGND &&
3650         message != WM_NCHITTEST &&
3651         message != WM_GETTEXT &&
3652         message != WM_MDIGETACTIVE &&
3653         !ignore_message( message ))
3654     {
3655         msg.hwnd = hwnd;
3656         msg.message = message;
3657         msg.flags = sent|wparam|lparam;
3658         msg.wParam = wParam;
3659         msg.lParam = lParam;
3660         msg.descr = "mdi client";
3661         add_message(&msg);
3662     }
3663 
3664     return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
3665 }
3666 
3667 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3668 {
3669     static LONG defwndproc_counter = 0;
3670     LRESULT ret;
3671     struct recvd_message msg;
3672 
3673     /* do not log painting messages */
3674     if (message != WM_PAINT &&
3675         message != WM_NCPAINT &&
3676         message != WM_SYNCPAINT &&
3677         message != WM_ERASEBKGND &&
3678         message != WM_NCHITTEST &&
3679         message != WM_GETTEXT &&
3680         !ignore_message( message ))
3681     {
3682         switch (message)
3683         {
3684             case WM_MDIACTIVATE:
3685             {
3686                 HWND active, client = GetParent(hwnd);
3687 
3688                 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
3689 
3690                 if (hwnd == (HWND)lParam) /* if we are being activated */
3691                     ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
3692                 else
3693                     ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
3694                 break;
3695             }
3696         }
3697 
3698         msg.hwnd = hwnd;
3699         msg.message = message;
3700         msg.flags = sent|wparam|lparam;
3701         if (defwndproc_counter) msg.flags |= defwinproc;
3702         msg.wParam = wParam;
3703         msg.lParam = lParam;
3704         msg.descr = "mdi child";
3705         add_message(&msg);
3706     }
3707 
3708     defwndproc_counter++;
3709     ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
3710     defwndproc_counter--;
3711 
3712     return ret;
3713 }
3714 
3715 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3716 {
3717     static LONG defwndproc_counter = 0;
3718     LRESULT ret;
3719     struct recvd_message msg;
3720 
3721     /* do not log painting messages */
3722     if (message != WM_PAINT &&
3723         message != WM_NCPAINT &&
3724         message != WM_SYNCPAINT &&
3725         message != WM_ERASEBKGND &&
3726         message != WM_NCHITTEST &&
3727         message != WM_GETTEXT &&
3728         !ignore_message( message ))
3729     {
3730         msg.hwnd = hwnd;
3731         msg.message = message;
3732         msg.flags = sent|wparam|lparam;
3733         if (defwndproc_counter) msg.flags |= defwinproc;
3734         msg.wParam = wParam;
3735         msg.lParam = lParam;
3736         msg.descr = "mdi frame";
3737         add_message(&msg);
3738     }
3739 
3740     defwndproc_counter++;
3741     ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
3742     defwndproc_counter--;
3743 
3744     return ret;
3745 }
3746 
3747 static BOOL mdi_RegisterWindowClasses(void)
3748 {
3749     WNDCLASSA cls;
3750 
3751     cls.style = 0;
3752     cls.lpfnWndProc = mdi_frame_wnd_proc;
3753     cls.cbClsExtra = 0;
3754     cls.cbWndExtra = 0;
3755     cls.hInstance = GetModuleHandleA(0);
3756     cls.hIcon = 0;
3757     cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
3758     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
3759     cls.lpszMenuName = NULL;
3760     cls.lpszClassName = "MDI_frame_class";
3761     if (!RegisterClassA(&cls)) return FALSE;
3762 
3763     cls.lpfnWndProc = mdi_child_wnd_proc;
3764     cls.lpszClassName = "MDI_child_class";
3765     if (!RegisterClassA(&cls)) return FALSE;
3766 
3767     if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
3768     old_mdi_client_proc = cls.lpfnWndProc;
3769     cls.hInstance = GetModuleHandleA(0);
3770     cls.lpfnWndProc = mdi_client_hook_proc;
3771     cls.lpszClassName = "MDI_client_class";
3772     if (!RegisterClassA(&cls)) assert(0);
3773 
3774     return TRUE;
3775 }
3776 
3777 static void test_mdi_messages(void)
3778 {
3779     MDICREATESTRUCTA mdi_cs;
3780     CLIENTCREATESTRUCT client_cs;
3781     HWND mdi_frame, mdi_child, mdi_child2, active_child;
3782     BOOL zoomed;
3783     RECT rc;
3784     HMENU hMenu = CreateMenu();
3785     LONG val;
3786 
3787     if (!mdi_RegisterWindowClasses()) assert(0);
3788 
3789     flush_sequence();
3790 
3791     trace("creating MDI frame window\n");
3792     mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
3793                                 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
3794                                 WS_MAXIMIZEBOX | WS_VISIBLE,
3795                                 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
3796                                 GetDesktopWindow(), hMenu,
3797                                 GetModuleHandleA(0), NULL);
3798     assert(mdi_frame);
3799     ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
3800 
3801     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3802     ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
3803 
3804     trace("creating MDI client window\n");
3805     GetClientRect(mdi_frame, &rc);
3806     client_cs.hWindowMenu = 0;
3807     client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
3808     mdi_client = CreateWindowExA(0, "MDI_client_class",
3809                                  NULL,
3810                                  WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
3811                                  rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
3812                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3813     assert(mdi_client);
3814     SetWindowLongA(mdi_client, 0, 0xdeadbeef);
3815 
3816     ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
3817     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3818     ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
3819 
3820     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3821     ok(!active_child, "wrong active MDI child %p\n", active_child);
3822     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3823 
3824     SetFocus(0);
3825     flush_sequence();
3826 
3827     trace("creating invisible MDI child window\n");
3828     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3829                                 WS_CHILD,
3830                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3831                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3832     assert(mdi_child);
3833 
3834     flush_sequence();
3835     ShowWindow(mdi_child, SW_SHOWNORMAL);
3836     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
3837 
3838     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3839     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3840 
3841     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3842     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3843 
3844     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3845     ok(!active_child, "wrong active MDI child %p\n", active_child);
3846     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3847 
3848     ShowWindow(mdi_child, SW_HIDE);
3849     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
3850     flush_sequence();
3851 
3852     ShowWindow(mdi_child, SW_SHOW);
3853     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
3854 
3855     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3856     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3857 
3858     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3859     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3860 
3861     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3862     ok(!active_child, "wrong active MDI child %p\n", active_child);
3863     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3864 
3865     DestroyWindow(mdi_child);
3866     flush_sequence();
3867 
3868     trace("creating visible MDI child window\n");
3869     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3870                                 WS_CHILD | WS_VISIBLE,
3871                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3872                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3873     assert(mdi_child);
3874     ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
3875 
3876     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3877     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3878 
3879     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3880     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3881 
3882     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3883     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3884     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3885     flush_sequence();
3886 
3887     DestroyWindow(mdi_child);
3888     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3889 
3890     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3891     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3892 
3893     /* Win2k: MDI client still returns a just destroyed child as active
3894      * Win9x: MDI client returns 0
3895      */
3896     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3897     ok(active_child == mdi_child || /* win2k */
3898        !active_child, /* win9x */
3899        "wrong active MDI child %p\n", active_child);
3900     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3901 
3902     flush_sequence();
3903 
3904     trace("creating invisible MDI child window\n");
3905     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3906                                 WS_CHILD,
3907                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3908                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3909     assert(mdi_child2);
3910     ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
3911 
3912     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
3913     ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
3914 
3915     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3916     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3917 
3918     /* Win2k: MDI client still returns a just destroyed child as active
3919      * Win9x: MDI client returns mdi_child2
3920      */
3921     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3922     ok(active_child == mdi_child || /* win2k */
3923        active_child == mdi_child2, /* win9x */
3924        "wrong active MDI child %p\n", active_child);
3925     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3926     flush_sequence();
3927 
3928     ShowWindow(mdi_child2, SW_MAXIMIZE);
3929     ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
3930 
3931     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3932     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3933 
3934     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3935     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3936     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3937     flush_sequence();
3938 
3939     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3940     ok(GetFocus() == mdi_child2 || /* win2k */
3941        GetFocus() == 0, /* win9x */
3942        "wrong focus window %p\n", GetFocus());
3943 
3944     SetFocus(0);
3945     flush_sequence();
3946 
3947     ShowWindow(mdi_child2, SW_HIDE);
3948     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3949 
3950     ShowWindow(mdi_child2, SW_RESTORE);
3951     ok_sequence(WmRestoreMDIchildInvisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
3952     flush_sequence();
3953 
3954     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3955     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3956 
3957     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3958     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3959     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3960     flush_sequence();
3961 
3962     SetFocus(0);
3963     flush_sequence();
3964 
3965     ShowWindow(mdi_child2, SW_HIDE);
3966     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3967 
3968     ShowWindow(mdi_child2, SW_SHOW);
3969     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
3970 
3971     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3972     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3973 
3974     ShowWindow(mdi_child2, SW_MAXIMIZE);
3975     ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
3976 
3977     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3978     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3979 
3980     ShowWindow(mdi_child2, SW_RESTORE);
3981     ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
3982 
3983     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3984     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3985 
3986     ShowWindow(mdi_child2, SW_MINIMIZE);
3987     ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", FALSE);
3988 
3989     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3990     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3991 
3992     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3993     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3994     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3995     flush_sequence();
3996 
3997     ShowWindow(mdi_child2, SW_RESTORE);
3998     ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", FALSE);
3999 
4000     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4001     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4002 
4003     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4004     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4005     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4006     flush_sequence();
4007 
4008     SetFocus(0);
4009     flush_sequence();
4010 
4011     ShowWindow(mdi_child2, SW_HIDE);
4012     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
4013 
4014     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4015     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4016 
4017     DestroyWindow(mdi_child2);
4018     ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
4019 
4020     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4021     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4022 
4023     trace("Testing WM_CHILDACTIVATE\n");
4024 
4025     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4026                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_DISABLED,
4027                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4028                                 mdi_client, 0, GetModuleHandleA(0), NULL);
4029 
4030     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4031                                  WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX,
4032                                  0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4033                                  mdi_client, 0, GetModuleHandleA(0), NULL);
4034 
4035     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4036     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4037     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4038 
4039     flush_sequence();
4040     SendMessageW(mdi_child, WM_CHILDACTIVATE, 0, 0);
4041     ok_sequence(WmChildActivateDisabledWindowSeq, "WM_CHILDACTIVATE sent to disabled window", FALSE);
4042 
4043     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4044     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4045     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4046     flush_sequence();
4047 
4048     EnableWindow(mdi_child, TRUE);
4049 
4050     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4051     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4052     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4053 
4054     flush_sequence();
4055     SendMessageW(mdi_child, WM_CHILDACTIVATE, 0, 0);
4056     ok_sequence(WmChildActivateWindowSeq, "WM_CHILDACTIVATE sent to enabled window", FALSE);
4057 
4058     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4059     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4060     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4061     flush_sequence();
4062 
4063     DestroyWindow(mdi_child);
4064     DestroyWindow(mdi_child2);
4065     flush_sequence();
4066 
4067     /* test for maximized MDI children */
4068     trace("creating maximized visible MDI child window 1\n");
4069     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4070                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4071                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4072                                 mdi_client, 0, GetModuleHandleA(0), NULL);
4073     assert(mdi_child);
4074     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
4075     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4076 
4077     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4078     ok(GetFocus() == mdi_child || /* win2k */
4079        GetFocus() == 0, /* win9x */
4080        "wrong focus window %p\n", GetFocus());
4081 
4082     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4083     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4084     ok(zoomed, "wrong zoomed state %d\n", zoomed);
4085     flush_sequence();
4086 
4087     trace("creating maximized visible MDI child window 2\n");
4088     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4089                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4090                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4091                                 mdi_client, 0, GetModuleHandleA(0), NULL);
4092     assert(mdi_child2);
4093     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
4094     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
4095     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4096 
4097     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4098     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4099 
4100     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4101     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4102     ok(zoomed, "wrong zoomed state %d\n", zoomed);
4103     flush_sequence();
4104 
4105     trace("destroying maximized visible MDI child window 2\n");
4106     DestroyWindow(mdi_child2);
4107     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
4108 
4109     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4110 
4111     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4112     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4113 
4114     /* Win2k: MDI client still returns a just destroyed child as active
4115      * Win9x: MDI client returns 0
4116      */
4117     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4118     ok(active_child == mdi_child2 || /* win2k */
4119        !active_child, /* win9x */
4120        "wrong active MDI child %p\n", active_child);
4121     flush_sequence();
4122 
4123     ShowWindow(mdi_child, SW_MAXIMIZE);
4124     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4125     flush_sequence();
4126 
4127     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4128     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4129 
4130     trace("re-creating maximized visible MDI child window 2\n");
4131     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4132                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4133                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4134                                 mdi_client, 0, GetModuleHandleA(0), NULL);
4135     assert(mdi_child2);
4136     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
4137     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
4138     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4139 
4140     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4141     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4142 
4143     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4144     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4145     ok(zoomed, "wrong zoomed state %d\n", zoomed);
4146     flush_sequence();
4147 
4148     SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
4149     ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
4150     ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
4151 
4152     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4153     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4154     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4155 
4156     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4157     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4158     ok(zoomed, "wrong zoomed state %d\n", zoomed);
4159     flush_sequence();
4160 
4161     DestroyWindow(mdi_child);
4162     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
4163 
4164     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4165     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4166 
4167     /* Win2k: MDI client still returns a just destroyed child as active
4168      * Win9x: MDI client returns 0
4169      */
4170     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4171     ok(active_child == mdi_child || /* win2k */
4172        !active_child, /* win9x */
4173        "wrong active MDI child %p\n", active_child);
4174     flush_sequence();
4175 
4176     trace("creating maximized invisible MDI child window\n");
4177     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4178                                 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
4179                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4180                                 mdi_client, 0, GetModuleHandleA(0), NULL);
4181     assert(mdi_child2);
4182     ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", FALSE);
4183     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
4184     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
4185     ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
4186 
4187     /* Win2k: MDI client still returns a just destroyed child as active
4188      * Win9x: MDI client returns 0
4189      */
4190     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4191     ok(active_child == mdi_child || /* win2k */
4192        !active_child || active_child == mdi_child2, /* win9x */
4193        "wrong active MDI child %p\n", active_child);
4194     flush_sequence();
4195 
4196     trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
4197     ShowWindow(mdi_child2, SW_MAXIMIZE);
4198     ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
4199     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
4200     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4201     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
4202 
4203     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4204     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4205     ok(zoomed, "wrong zoomed state %d\n", zoomed);
4206     flush_sequence();
4207 
4208     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
4209     flush_sequence();
4210 
4211     /* end of test for maximized MDI children */
4212     SetFocus(0);
4213     flush_sequence();
4214     trace("creating maximized visible MDI child window 1(Switch test)\n");
4215     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4216                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4217                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4218                                 mdi_client, 0, GetModuleHandleA(0), NULL);
4219     assert(mdi_child);
4220     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE);
4221     ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n");
4222 
4223     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
4224     ok(GetFocus() == mdi_child || /* win2k */
4225        GetFocus() == 0, /* win9x */
4226        "wrong focus window %p(Switch test)\n", GetFocus());
4227 
4228     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4229     ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
4230     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
4231     flush_sequence();
4232 
4233     trace("creating maximized visible MDI child window 2(Switch test)\n");
4234     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4235                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4236                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4237                                 mdi_client, 0, GetModuleHandleA(0), NULL);
4238     assert(mdi_child2);
4239     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child window (Switch test)", TRUE);
4240 
4241     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n");
4242     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized(Switch test)\n");
4243 
4244     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
4245     ok(GetFocus() == mdi_child2, "wrong focus window %p(Switch test)\n", GetFocus());
4246 
4247     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4248     ok(active_child == mdi_child2, "wrong active MDI child %p(Switch test)\n", active_child);
4249     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
4250     flush_sequence();
4251 
4252     trace("Switch child window.\n");
4253     SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0);
4254     ok_sequence(WmSwitchChild, "Child did not switch correctly", TRUE);
4255     trace("end of test for switch maximized MDI children\n");
4256     flush_sequence();
4257 
4258     /* Prepare for switching test of not maximized MDI children  */
4259     ShowWindow( mdi_child, SW_NORMAL );
4260     ok(!IsZoomed(mdi_child), "wrong zoomed state for %p(Switch test)\n", mdi_child);
4261     ok(!IsZoomed(mdi_child2), "wrong zoomed state for %p(Switch test)\n", mdi_child2);
4262     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
4263     ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
4264     flush_sequence();
4265 
4266     SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child2, 0);
4267     ok_sequence(WmSwitchNotMaximizedChild, "Not maximized child did not switch correctly", FALSE);
4268     trace("end of test for switch not maximized MDI children\n");
4269     flush_sequence();
4270 
4271     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
4272     flush_sequence();
4273 
4274     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
4275     flush_sequence();
4276 
4277     SetFocus(0);
4278     flush_sequence();
4279     /* end of tests for switch maximized/not maximized MDI children */
4280 
4281     mdi_cs.szClass = "MDI_child_Class";
4282     mdi_cs.szTitle = "MDI child";
4283     mdi_cs.hOwner = GetModuleHandleA(0);
4284     mdi_cs.x = 0;
4285     mdi_cs.y = 0;
4286     mdi_cs.cx = CW_USEDEFAULT;
4287     mdi_cs.cy = CW_USEDEFAULT;
4288     mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
4289     mdi_cs.lParam = 0;
4290     mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
4291     ok(mdi_child != 0, "MDI child creation failed\n");
4292     ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
4293 
4294     ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
4295 
4296     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4297     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4298 
4299     ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
4300     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4301     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4302 
4303     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4304     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4305     ok(zoomed, "wrong zoomed state %d\n", zoomed);
4306     flush_sequence();
4307 
4308     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
4309     ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
4310 
4311     ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
4312     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4313     ok(!active_child, "wrong active MDI child %p\n", active_child);
4314 
4315     SetFocus(0);
4316     flush_sequence();
4317 
4318     val = GetWindowLongA(mdi_client, 0);
4319     ok(val == 0xdeadbeef || broken(val == 0) /* >= Win Vista */, "Expected 0xdeadbeef, got 0x%x\n", val);
4320     DestroyWindow(mdi_client);
4321     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
4322 
4323     /* test maximization of MDI child with invisible parent */
4324     client_cs.hWindowMenu = 0;
4325     mdi_client = CreateWindowA("MDI_client_class",
4326                                  NULL,
4327                                  WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
4328                                  0, 0, 660, 430,
4329                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
4330     ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
4331 
4332     ShowWindow(mdi_client, SW_HIDE);
4333     ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
4334 
4335     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4336                                 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
4337                                 0, 0, 650, 440,
4338                                 mdi_client, 0, GetModuleHandleA(0), NULL);
4339     ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
4340 
4341     SendMessageA(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
4342     ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
4343     zoomed = IsZoomed(mdi_child);
4344     ok(zoomed, "wrong zoomed state %d\n", zoomed);
4345 
4346     ShowWindow(mdi_client, SW_SHOW);
4347     ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
4348 
4349     DestroyWindow(mdi_child);
4350     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
4351 
4352     /* end of test for maximization of MDI child with invisible parent */
4353 
4354     DestroyWindow(mdi_client);
4355     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
4356 
4357     DestroyWindow(mdi_frame);
4358     ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
4359 }
4360 /************************* End of MDI test **********************************/
4361 
4362 static void test_WM_SETREDRAW(HWND hwnd)
4363 {
4364     DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
4365 
4366     flush_events();
4367     flush_sequence();
4368 
4369     SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
4370     ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
4371 
4372     ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
4373     ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
4374 
4375     flush_sequence();
4376     SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
4377     ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
4378 
4379     ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4380     ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
4381 
4382     /* restore original WS_VISIBLE state */
4383     SetWindowLongA(hwnd, GWL_STYLE, style);
4384 
4385     flush_events();
4386     flush_sequence();
4387 }
4388 
4389 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4390 {
4391     struct recvd_message msg;
4392 
4393     if (ignore_message( message )) return 0;
4394 
4395     switch (message)
4396     {
4397 	/* ignore */
4398 	case WM_MOUSEMOVE:
4399 	case WM_NCMOUSEMOVE:
4400 	case WM_NCMOUSELEAVE:
4401 	case WM_SETCURSOR:
4402             return 0;
4403         case WM_NCHITTEST:
4404             return HTCLIENT;
4405     }
4406 
4407     msg.hwnd = hwnd;
4408     msg.message = message;
4409     msg.flags = sent|wparam|lparam;
4410     msg.wParam = wParam;
4411     msg.lParam = lParam;
4412     msg.descr = "dialog";
4413     add_message(&msg);
4414 
4415     if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
4416     if (message == WM_TIMER) EndDialog( hwnd, 0 );
4417     return 0;
4418 }
4419 
4420 static INT_PTR CALLBACK TestModalDlgProc2(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4421 {
4422     struct recvd_message msg;
4423 
4424     if (ignore_message( message )) return 0;
4425 
4426     switch (message)
4427     {
4428 	/* ignore */
4429 	case WM_MOUSEMOVE:
4430 	case WM_NCMOUSEMOVE:
4431 	case WM_NCMOUSELEAVE:
4432 	case WM_SETCURSOR:
4433             return 0;
4434         case WM_NCHITTEST:
4435             return HTCLIENT;
4436     }
4437 
4438     msg.hwnd = hwnd;
4439     msg.message = message;
4440     msg.flags = sent|wparam|lparam;
4441     msg.wParam = wParam;
4442     msg.lParam = lParam;
4443     msg.descr = "dialog";
4444     add_message(&msg);
4445 
4446     if (message == WM_INITDIALOG) EndDialog( hwnd, 0 );
4447     return 0;
4448 }
4449 
4450 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4451 {
4452     DWORD style, exstyle;
4453     INT xmin, xmax;
4454     BOOL ret;
4455 
4456     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4457     style = GetWindowLongA(hwnd, GWL_STYLE);
4458     /* do not be confused by WS_DLGFRAME set */
4459     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4460 
4461     if (clear) ok(style & clear, "style %08x should be set\n", clear);
4462     if (set) ok(!(style & set), "style %08x should not be set\n", set);
4463 
4464     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4465     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
4466     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4467         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
4468     else
4469         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
4470 
4471     style = GetWindowLongA(hwnd, GWL_STYLE);
4472     if (set) ok(style & set, "style %08x should be set\n", set);
4473     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4474 
4475     /* a subsequent call should do nothing */
4476     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4477     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
4478     ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4479 
4480     xmin = 0xdeadbeef;
4481     xmax = 0xdeadbeef;
4482     ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
4483     ok( ret, "GetScrollRange(%d) error %d\n", ctl, GetLastError());
4484     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4485     ok(xmin == min, "unexpected min scroll value %d\n", xmin);
4486     ok(xmax == max, "unexpected max scroll value %d\n", xmax);
4487 }
4488 
4489 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4490 {
4491     DWORD style, exstyle;
4492     SCROLLINFO si;
4493     BOOL ret;
4494 
4495     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4496     style = GetWindowLongA(hwnd, GWL_STYLE);
4497     /* do not be confused by WS_DLGFRAME set */
4498     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4499 
4500     if (clear) ok(style & clear, "style %08x should be set\n", clear);
4501     if (set) ok(!(style & set), "style %08x should not be set\n", set);
4502 
4503     si.cbSize = sizeof(si);
4504     si.fMask = SIF_RANGE;
4505     si.nMin = min;
4506     si.nMax = max;
4507     SetScrollInfo(hwnd, ctl, &si, TRUE);
4508     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4509         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
4510     else
4511         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
4512 
4513     style = GetWindowLongA(hwnd, GWL_STYLE);
4514     if (set) ok(style & set, "style %08x should be set\n", set);
4515     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4516 
4517     /* a subsequent call should do nothing */
4518     SetScrollInfo(hwnd, ctl, &si, TRUE);
4519     if (style & WS_HSCROLL)
4520         ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4521     else if (style & WS_VSCROLL)
4522         ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4523     else
4524         ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4525 
4526     si.fMask = SIF_PAGE;
4527     si.nPage = 5;
4528     SetScrollInfo(hwnd, ctl, &si, FALSE);
4529     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4530 
4531     si.fMask = SIF_POS;
4532     si.nPos = max - 1;
4533     SetScrollInfo(hwnd, ctl, &si, FALSE);
4534     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4535 
4536     si.fMask = SIF_RANGE;
4537     si.nMin = 0xdeadbeef;
4538     si.nMax = 0xdeadbeef;
4539     ret = GetScrollInfo(hwnd, ctl, &si);
4540     ok( ret, "GetScrollInfo error %d\n", GetLastError());
4541     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4542     ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
4543     ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
4544 }
4545 
4546 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
4547 static void test_scroll_messages(HWND hwnd)
4548 {
4549     SCROLLINFO si;
4550     INT min, max;
4551     BOOL ret;
4552 
4553     flush_events();
4554     flush_sequence();
4555 
4556     min = 0xdeadbeef;
4557     max = 0xdeadbeef;
4558     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4559     ok( ret, "GetScrollRange error %d\n", GetLastError());
4560     if (sequence->message != WmGetScrollRangeSeq[0].message)
4561         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4562     /* values of min and max are undefined */
4563     flush_sequence();
4564 
4565     ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
4566     ok( ret, "SetScrollRange error %d\n", GetLastError());
4567     if (sequence->message != WmSetScrollRangeSeq[0].message)
4568         trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4569     flush_sequence();
4570 
4571     min = 0xdeadbeef;
4572     max = 0xdeadbeef;
4573     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4574     ok( ret, "GetScrollRange error %d\n", GetLastError());
4575     if (sequence->message != WmGetScrollRangeSeq[0].message)
4576         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4577     /* values of min and max are undefined */
4578     flush_sequence();
4579 
4580     si.cbSize = sizeof(si);
4581     si.fMask = SIF_RANGE;
4582     si.nMin = 20;
4583     si.nMax = 160;
4584     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4585     if (sequence->message != WmSetScrollRangeSeq[0].message)
4586         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4587     flush_sequence();
4588 
4589     si.fMask = SIF_PAGE;
4590     si.nPage = 10;
4591     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4592     if (sequence->message != WmSetScrollRangeSeq[0].message)
4593         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4594     flush_sequence();
4595 
4596     si.fMask = SIF_POS;
4597     si.nPos = 20;
4598     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4599     if (sequence->message != WmSetScrollRangeSeq[0].message)
4600         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4601     flush_sequence();
4602 
4603     si.fMask = SIF_RANGE;
4604     si.nMin = 0xdeadbeef;
4605     si.nMax = 0xdeadbeef;
4606     ret = GetScrollInfo(hwnd, SB_CTL, &si);
4607     ok( ret, "GetScrollInfo error %d\n", GetLastError());
4608     if (sequence->message != WmGetScrollInfoSeq[0].message)
4609         trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4610     /* values of min and max are undefined */
4611     flush_sequence();
4612 
4613     /* set WS_HSCROLL */
4614     test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4615     /* clear WS_HSCROLL */
4616     test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4617 
4618     /* set WS_HSCROLL */
4619     test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4620     /* clear WS_HSCROLL */
4621     test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4622 
4623     /* set WS_VSCROLL */
4624     test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4625     /* clear WS_VSCROLL */
4626     test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4627 
4628     /* set WS_VSCROLL */
4629     test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4630     /* clear WS_VSCROLL */
4631     test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4632 }
4633 
4634 static void test_showwindow(void)
4635 {
4636     HWND hwnd, hchild;
4637     RECT rc;
4638 
4639     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4640                            100, 100, 200, 200, 0, 0, 0, NULL);
4641     ok (hwnd != 0, "Failed to create overlapped window\n");
4642     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4643                              0, 0, 10, 10, hwnd, 0, 0, NULL);
4644     ok (hchild != 0, "Failed to create child\n");
4645     flush_sequence();
4646 
4647     /* ShowWindow( SW_SHOWNA) for invisible top level window */
4648     trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
4649     ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4650     ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", FALSE);
4651 
4652     /* ShowWindow( SW_SHOWNA) for now visible top level window */
4653     trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
4654     ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4655     ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
4656     /* back to invisible */
4657     ShowWindow(hchild, SW_HIDE);
4658     ShowWindow(hwnd, SW_HIDE);
4659     flush_sequence();
4660     /* ShowWindow(SW_SHOWNA) with child and parent invisible */
4661     trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
4662     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4663     ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
4664     /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */
4665     ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
4666     flush_sequence();
4667     trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
4668     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4669     ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
4670     /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
4671     ShowWindow( hwnd, SW_SHOW);
4672     flush_sequence();
4673     trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
4674     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4675     ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
4676 
4677     /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
4678     ShowWindow( hchild, SW_HIDE);
4679     flush_sequence();
4680     trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
4681     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4682     ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
4683 
4684     SetCapture(hchild);
4685     ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
4686     DestroyWindow(hchild);
4687     ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
4688 
4689     DestroyWindow(hwnd);
4690     flush_sequence();
4691 
4692     /* Popup windows */
4693     /* Test 1:
4694      * 1. Create invisible maximized popup window.
4695      * 2. Move and resize it.
4696      * 3. Show it maximized.
4697      */
4698     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4699     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4700                            100, 100, 200, 200, 0, 0, 0, NULL);
4701     ok (hwnd != 0, "Failed to create popup window\n");
4702     ok(IsZoomed(hwnd), "window should be maximized\n");
4703     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4704 
4705     GetWindowRect(hwnd, &rc);
4706     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4707         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4708         "Invalid maximized size before ShowWindow %s\n", wine_dbgstr_rect( &rc ));
4709     /* Reset window's size & position */
4710     SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
4711     ok(IsZoomed(hwnd), "window should be maximized\n");
4712     flush_sequence();
4713 
4714     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4715     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4716     ok(IsZoomed(hwnd), "window should be maximized\n");
4717     ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
4718 
4719     GetWindowRect(hwnd, &rc);
4720     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4721         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4722         "Invalid maximized size after ShowWindow %s\n", wine_dbgstr_rect( &rc ));
4723     DestroyWindow(hwnd);
4724     flush_sequence();
4725 
4726     /* Test 2:
4727      * 1. Create invisible maximized popup window.
4728      * 2. Show it maximized.
4729      */
4730     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4731     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4732                            100, 100, 200, 200, 0, 0, 0, NULL);
4733     ok (hwnd != 0, "Failed to create popup window\n");
4734     ok(IsZoomed(hwnd), "window should be maximized\n");
4735     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4736 
4737     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4738     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4739     ok(IsZoomed(hwnd), "window should be maximized\n");
4740     ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
4741     DestroyWindow(hwnd);
4742     flush_sequence();
4743 
4744     /* Test 3:
4745      * 1. Create visible maximized popup window.
4746      */
4747     trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
4748     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
4749                            100, 100, 200, 200, 0, 0, 0, NULL);
4750     ok (hwnd != 0, "Failed to create popup window\n");
4751     ok(IsZoomed(hwnd), "window should be maximized\n");
4752     ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4753     DestroyWindow(hwnd);
4754     flush_sequence();
4755 
4756     /* Test 4:
4757      * 1. Create visible popup window.
4758      * 2. Maximize it.
4759      */
4760     trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
4761     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
4762                            100, 100, 200, 200, 0, 0, 0, NULL);
4763     ok (hwnd != 0, "Failed to create popup window\n");
4764     ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
4765     ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE);
4766 
4767     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
4768     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4769     ok(IsZoomed(hwnd), "window should be maximized\n");
4770     ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
4771     DestroyWindow(hwnd);
4772     flush_sequence();
4773 }
4774 
4775 static void test_recursive_activation(void)
4776 {
4777     static const struct message seq[] =
4778     {
4779         { HCBT_ACTIVATE, hook },
4780         { WM_NCACTIVATE, sent|wparam, TRUE },
4781         { WM_ACTIVATE, sent|wparam, WA_ACTIVE },
4782         { HCBT_ACTIVATE, hook },
4783         { WM_NCACTIVATE, sent|wparam, FALSE },
4784         { WM_ACTIVATE, sent|wparam, WA_INACTIVE },
4785         { WM_SETFOCUS, sent|optional },
4786         { 0 }
4787     };
4788     HWND hwnd, recursive;
4789 
4790     hwnd = CreateWindowExA(0, "SimpleWindowClass", NULL, WS_OVERLAPPED|WS_VISIBLE,
4791                               100, 100, 200, 200, 0, 0, 0, NULL);
4792     ok(hwnd != 0, "Failed to create simple window\n");
4793 
4794     recursive = CreateWindowExA(0, "RecursiveActivationClass", NULL, WS_OVERLAPPED|WS_VISIBLE,
4795                                 10, 10, 50, 50, hwnd, 0, 0, NULL);
4796     ok(recursive != 0, "Failed to create recursive activation window\n");
4797     SetActiveWindow(hwnd);
4798 
4799     flush_sequence();
4800     SetActiveWindow(recursive);
4801     ok_sequence(seq, "Recursive Activation", FALSE);
4802 
4803     DestroyWindow(recursive);
4804     DestroyWindow(hwnd);
4805     flush_sequence();
4806 }
4807 
4808 static void test_sys_menu(void)
4809 {
4810     HWND hwnd;
4811     HMENU hmenu;
4812     UINT state;
4813 
4814     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4815                            100, 100, 200, 200, 0, 0, 0, NULL);
4816     ok (hwnd != 0, "Failed to create overlapped window\n");
4817 
4818     flush_sequence();
4819 
4820     /* test existing window without CS_NOCLOSE style */
4821     hmenu = GetSystemMenu(hwnd, FALSE);
4822     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4823 
4824     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4825     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4826     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4827 
4828     EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
4829     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4830 
4831     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4832     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4833     ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
4834 
4835     EnableMenuItem(hmenu, SC_CLOSE, 0);
4836     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4837 
4838     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4839     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4840     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4841 
4842     /* test whether removing WS_SYSMENU destroys a system menu */
4843     SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
4844     SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4845     flush_sequence();
4846     hmenu = GetSystemMenu(hwnd, FALSE);
4847     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4848 
4849     DestroyWindow(hwnd);
4850 
4851     /* test new window with CS_NOCLOSE style */
4852     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4853                            100, 100, 200, 200, 0, 0, 0, NULL);
4854     ok (hwnd != 0, "Failed to create overlapped window\n");
4855 
4856     hmenu = GetSystemMenu(hwnd, FALSE);
4857     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4858 
4859     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4860     ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4861 
4862     DestroyWindow(hwnd);
4863 
4864     /* test new window without WS_SYSMENU style */
4865     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
4866                            100, 100, 200, 200, 0, 0, 0, NULL);
4867     ok(hwnd != 0, "Failed to create overlapped window\n");
4868 
4869     hmenu = GetSystemMenu(hwnd, FALSE);
4870     ok(!hmenu, "GetSystemMenu error %d\n", GetLastError());
4871 
4872     DestroyWindow(hwnd);
4873 }
4874 
4875 /* For shown WS_OVERLAPPEDWINDOW */
4876 static const struct message WmSetIcon_1[] = {
4877     { WM_SETICON, sent },
4878     { 0x00AE, sent|defwinproc|optional }, /* XP */
4879     { WM_GETTEXT, sent|defwinproc|optional },
4880     { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
4881     { 0 }
4882 };
4883 
4884 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
4885 static const struct message WmSetIcon_2[] = {
4886     { WM_SETICON, sent },
4887     { 0 }
4888 };
4889 
4890 /* Sending undocumented 0x3B message with wparam = 0x8000000b */
4891 static const struct message WmInitEndSession[] = {
4892     { 0x003B, sent },
4893     { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4894     { 0 }
4895 };
4896 
4897 /* Sending undocumented 0x3B message with wparam = 0x0000000b */
4898 static const struct message WmInitEndSession_2[] = {
4899     { 0x003B, sent },
4900     { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4901     { 0 }
4902 };
4903 
4904 /* Sending undocumented 0x3B message with wparam = 0x80000008 */
4905 static const struct message WmInitEndSession_3[] = {
4906     { 0x003B, sent },
4907     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4908     { 0 }
4909 };
4910 
4911 /* Sending undocumented 0x3B message with wparam = 0x00000008 */
4912 static const struct message WmInitEndSession_4[] = {
4913     { 0x003B, sent },
4914     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4915     { 0 }
4916 };
4917 
4918 /* Sending undocumented 0x3B message with wparam = 0x80000001 */
4919 static const struct message WmInitEndSession_5[] = {
4920     { 0x003B, sent },
4921     { WM_ENDSESSION, sent|defwinproc/*|wparam*/|lparam, 1, ENDSESSION_LOGOFF },
4922     { 0 }
4923 };
4924 
4925 static const struct message WmOptionalPaint[] = {
4926     { WM_PAINT, sent|optional },
4927     { WM_NCPAINT, sent|beginpaint|optional },
4928     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4929     { WM_ERASEBKGND, sent|beginpaint|optional },
4930     { 0 }
4931 };
4932 
4933 static const struct message WmZOrder[] = {
4934     { WM_WINDOWPOSCHANGING, sent|wparam, 0, 0 },
4935     { WM_GETMINMAXINFO, sent|defwinproc|wparam, 0, 0 },
4936     { HCBT_ACTIVATE, hook },
4937     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
4938     { WM_WINDOWPOSCHANGING, sent|wparam, 3, 0 },
4939     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0 },
4940     { WM_GETTEXT, sent|optional },
4941     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
4942     { WM_ACTIVATEAPP, sent|wparam, 1, 0 },
4943     { WM_NCACTIVATE, sent|lparam, 1, 0 },
4944     { WM_GETTEXT, sent|defwinproc|optional },
4945     { WM_GETTEXT, sent|defwinproc|optional },
4946     { WM_ACTIVATE, sent|wparam|lparam, 1, 0 },
4947     { HCBT_SETFOCUS, hook },
4948     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
4949     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4950     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
4951     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
4952     { WM_GETTEXT, sent|optional },
4953     { WM_NCCALCSIZE, sent|optional },
4954     { 0 }
4955 };
4956 
4957 static void CALLBACK apc_test_proc(ULONG_PTR param)
4958 {
4959     /* nothing */
4960 }
4961 
4962 static void test_MsgWaitForMultipleObjects(HWND hwnd)
4963 {
4964     DWORD ret;
4965     MSG msg;
4966 
4967     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4968     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4969 
4970     PostMessageA(hwnd, WM_USER, 0, 0);
4971 
4972     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4973     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4974 
4975     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4976     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4977 
4978     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4979     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4980 
4981     PostMessageA(hwnd, WM_USER, 0, 0);
4982 
4983     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4984     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4985 
4986     ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
4987     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4988 
4989     /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
4990     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4991     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4992 
4993     PostMessageA(hwnd, WM_USER, 0, 0);
4994 
4995     /* new incoming message causes it to become signaled again */
4996     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4997     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4998 
4999     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5000     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5001     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5002     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5003 
5004     /* MWMO_INPUTAVAILABLE should succeed even if the message was already seen */
5005     PostMessageA( hwnd, WM_USER, 0, 0 );
5006     ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
5007     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5008 
5009     ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_INPUTAVAILABLE );
5010     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5011 
5012     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5013     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5014 
5015     /* without MWMO_ALERTABLE the result is never WAIT_IO_COMPLETION */
5016     ret = QueueUserAPC( apc_test_proc, GetCurrentThread(), 0 );
5017     ok(ret, "QueueUserAPC failed %u\n", GetLastError());
5018 
5019     ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, 0 );
5020     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5021 
5022     /* but even with MWMO_ALERTABLE window events are preferred */
5023     PostMessageA( hwnd, WM_USER, 0, 0 );
5024 
5025     ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_ALERTABLE );
5026     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5027 
5028     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5029     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5030 
5031     /* the APC call is still queued */
5032     ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_ALERTABLE );
5033     ok(ret == WAIT_IO_COMPLETION, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5034 }
5035 
5036 static void test_WM_DEVICECHANGE(HWND hwnd)
5037 {
5038     DWORD ret;
5039     MSG msg;
5040     int i;
5041     static const WPARAM wparams[] = {0,
5042                                      DBT_DEVNODES_CHANGED,
5043                                      DBT_QUERYCHANGECONFIG,
5044                                      DBT_CONFIGCHANGED,
5045                                      DBT_CONFIGCHANGECANCELED,
5046                                      DBT_NO_DISK_SPACE,
5047                                      DBT_LOW_DISK_SPACE,
5048                                      DBT_CONFIGMGPRIVATE, /* 0x7fff */
5049                                      DBT_DEVICEARRIVAL,   /* 0x8000 */
5050                                      DBT_DEVICEQUERYREMOVE,
5051                                      DBT_DEVICEQUERYREMOVEFAILED,
5052                                      DBT_DEVICEREMOVEPENDING,
5053                                      DBT_DEVICEREMOVECOMPLETE,
5054                                      DBT_DEVICETYPESPECIFIC,
5055                                      DBT_CUSTOMEVENT};
5056 
5057     for (i = 0; i < ARRAY_SIZE(wparams); i++)
5058     {
5059         SetLastError(0xdeadbeef);
5060         ret = PostMessageA(hwnd, WM_DEVICECHANGE, wparams[i], 0);
5061         if (wparams[i] & 0x8000)
5062         {
5063             ok(ret == FALSE, "PostMessage should returned %d\n", ret);
5064             ok(GetLastError() == ERROR_MESSAGE_SYNC_ONLY, "PostMessage error %08x\n", GetLastError());
5065         }
5066         else
5067         {
5068             ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5069             ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
5070             memset(&msg, 0, sizeof(msg));
5071             ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should succeed\n");
5072             ok(msg.message == WM_DEVICECHANGE, "got %04x instead of WM_DEVICECHANGE\n", msg.message);
5073         }
5074     }
5075 }
5076 
5077 static DWORD CALLBACK show_window_thread(LPVOID arg)
5078 {
5079    HWND hwnd = arg;
5080 
5081    /* function will not return if ShowWindow(SW_HIDE) calls SendMessage() */
5082    ok(ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow(SW_HIDE) expected FALSE\n");
5083 
5084    return 0;
5085 }
5086 
5087 /* Helper function to easier test SetWindowPos messages */
5088 #define test_msg_setpos( expected_list, flags, todo ) \
5089         test_msg_setpos_( (expected_list), (flags), (todo), __FILE__, __LINE__)
5090 static void test_msg_setpos_(const struct message *expected_list, UINT flags, BOOL todo, const char *file, int line)
5091 {
5092     HWND hwnd;
5093 
5094     flush_events();
5095     flush_sequence();
5096     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5097                              10, 10, 100, 100, NULL, 0, 0, NULL );
5098     ok (hwnd != 0, "Failed to create popup window\n");
5099     SetWindowPos(hwnd, NULL, 0, 0, 100, 100, flags);
5100     ok_sequence_(expected_list, "SetWindowPos:show_popup_first_show_window", todo, file, line);
5101     DestroyWindow(hwnd);
5102 }
5103 
5104 /* test if we receive the right sequence of messages */
5105 static void test_messages(void)
5106 {
5107     DWORD tid;
5108     HANDLE hthread;
5109     HWND hwnd, hparent, hchild;
5110     HWND hchild2, hbutton;
5111     HMENU hmenu;
5112     MSG msg;
5113     LRESULT res;
5114     POINT pos;
5115     BOOL ret;
5116 
5117     flush_sequence();
5118 
5119     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5120                            100, 100, 200, 200, 0, 0, 0, NULL);
5121     ok (hwnd != 0, "Failed to create overlapped window\n");
5122     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
5123 
5124     /* test ShowWindow(SW_HIDE) on a newly created invisible window */
5125     ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
5126     ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
5127 
5128     /* test WM_SETREDRAW on a not visible top level window */
5129     test_WM_SETREDRAW(hwnd);
5130 
5131     SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5132     flush_events();
5133     ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
5134     ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
5135 
5136     ok(GetActiveWindow() == hwnd, "window should be active\n");
5137     ok(GetFocus() == hwnd, "window should have input focus\n");
5138     ShowWindow(hwnd, SW_HIDE);
5139     flush_events();
5140     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5141 
5142     /* test ShowWindow(SW_HIDE) on a hidden window - single threaded */
5143     ok(ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow(SW_HIDE) expected FALSE\n");
5144     flush_events();
5145     ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5146 
5147     /* test ShowWindow(SW_HIDE) on a hidden window -  multi-threaded */
5148     hthread = CreateThread(NULL, 0, show_window_thread, hwnd, 0, &tid);
5149     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
5150     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5151     CloseHandle(hthread);
5152     flush_events();
5153     ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5154 
5155     ShowWindow(hwnd, SW_SHOW);
5156     flush_events();
5157     ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
5158 
5159     ShowWindow(hwnd, SW_HIDE);
5160     flush_events();
5161     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5162 
5163     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5164     flush_events();
5165     ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
5166     flush_sequence();
5167 
5168     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZE)
5169     {
5170         ShowWindow(hwnd, SW_RESTORE);
5171         flush_events();
5172         ok_sequence(WmShowRestoreMaxOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
5173         flush_sequence();
5174     }
5175 
5176     ShowWindow(hwnd, SW_MINIMIZE);
5177     flush_events();
5178     ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", FALSE);
5179     flush_sequence();
5180 
5181     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE)
5182     {
5183         ShowWindow(hwnd, SW_RESTORE);
5184         flush_events();
5185         ok_sequence(WmShowRestoreMinOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
5186         flush_sequence();
5187     }
5188 
5189     ShowWindow(hwnd, SW_SHOW);
5190     flush_events();
5191     ok_sequence(WmOptionalPaint, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
5192 
5193     SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5194     ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
5195     ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
5196     ok(GetActiveWindow() == hwnd, "window should still be active\n");
5197 
5198     /* test WM_SETREDRAW on a visible top level window */
5199     ShowWindow(hwnd, SW_SHOW);
5200     flush_events();
5201     test_WM_SETREDRAW(hwnd);
5202 
5203     trace("testing scroll APIs on a visible top level window %p\n", hwnd);
5204     test_scroll_messages(hwnd);
5205 
5206     /* test resizing and moving */
5207     SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
5208     ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
5209     flush_events();
5210     flush_sequence();
5211     SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
5212     ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
5213     flush_events();
5214     flush_sequence();
5215     SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER|SWP_NOACTIVATE );
5216     ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
5217     flush_events();
5218     flush_sequence();
5219 
5220     /* popups don't get WM_GETMINMAXINFO */
5221     SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
5222     SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
5223     flush_sequence();
5224     SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
5225     ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
5226 
5227     DestroyWindow(hwnd);
5228     ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
5229 
5230     /* Test if windows are correctly drawn when first shown */
5231 
5232     /* Visible, redraw */
5233     flush_events();
5234     flush_sequence();
5235     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5236                              10, 10, 100, 100, NULL, 0, 0, NULL );
5237     ok (hwnd != 0, "Failed to create popup window\n");
5238     RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
5239     ok_sequence(WmShowPopupFirstDrawSeq_1, "RedrawWindow:show_popup_first_draw_visible", FALSE);
5240     DestroyWindow(hwnd);
5241 
5242     /* Invisible, show, message */
5243     flush_events();
5244     flush_sequence();
5245     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5246                              10, 10, 100, 100, NULL, 0, 0, NULL );
5247     ok (hwnd != 0, "Failed to create popup window\n");
5248     ShowWindow(hwnd, SW_SHOW);
5249     SendMessageW(hwnd, WM_PAINT, 0, 0);
5250     ok_sequence(WmShowPopupFirstDrawSeq_1, "RedrawWindow:show_popup_first_draw_show", FALSE);
5251     DestroyWindow(hwnd);
5252 
5253     /* Invisible, show maximized, redraw */
5254     flush_events();
5255     flush_sequence();
5256     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5257                              10, 10, 100, 100, NULL, 0, 0, NULL );
5258     ok (hwnd != 0, "Failed to create popup window\n");
5259     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5260     RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
5261     ok_sequence(WmShowPopupFirstDrawSeq_2, "RedrawWindow:show_popup_first_draw_show_maximized", FALSE);
5262     DestroyWindow(hwnd);
5263 
5264     /* Test SetWindowPos */
5265     test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW, FALSE);
5266     test_msg_setpos(WmFirstDrawSetWindowPosSeq2, 0, FALSE);
5267     test_msg_setpos(WmFirstDrawSetWindowPosSeq3,
5268             SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER, FALSE);
5269 
5270     test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOSIZE, FALSE);
5271     test_msg_setpos(WmFirstDrawSetWindowPosSeq4, SWP_SHOWWINDOW | SWP_NOMOVE, FALSE);
5272     test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCLIENTSIZE, FALSE);
5273     test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCLIENTMOVE, FALSE);
5274     test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOZORDER, FALSE);
5275 
5276     test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE, FALSE);
5277     test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOCLIENTMOVE, FALSE);
5278     test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOCLIENTSIZE, FALSE);
5279     test_msg_setpos(WmFirstDrawSetWindowPosSeq5, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOMOVE, FALSE);
5280     test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOSIZE, FALSE);
5281     test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOZORDER, FALSE);
5282 
5283     test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS, FALSE);
5284     test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOCLIENTMOVE, FALSE);
5285     test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOCLIENTSIZE, FALSE);
5286     test_msg_setpos(WmFirstDrawSetWindowPosSeq4, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOMOVE, FALSE);
5287     test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOSIZE, FALSE);
5288     test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOZORDER, FALSE);
5289 
5290     test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW, FALSE);
5291     test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOCLIENTMOVE, FALSE);
5292     test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOCLIENTSIZE, FALSE);
5293     test_msg_setpos(WmFirstDrawSetWindowPosSeq5, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOMOVE, FALSE);
5294     test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOSIZE, FALSE);
5295     test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOZORDER, FALSE);
5296 
5297     /* Test SetWindowPos with child windows */
5298     flush_events();
5299     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5300                               100, 100, 200, 200, 0, 0, 0, NULL);
5301     ok (hparent != 0, "Failed to create parent window\n");
5302 
5303     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5304                              0, 0, 10, 10, hparent, 0, 0, NULL);
5305     ok (hchild != 0, "Failed to create child window\n");
5306     flush_sequence();
5307     SetWindowPos(hparent, NULL, 0, 0, 100, 100, SWP_SHOWWINDOW);
5308     ok_sequence(WmFirstDrawChildSeq1, /* Expect no messages for the child */
5309                 "SetWindowPos:show_popup_first_show_window_child1", FALSE);
5310     DestroyWindow(hchild);
5311     DestroyWindow(hparent);
5312 
5313     flush_events();
5314     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN,
5315                               100, 100, 200, 200, 0, 0, 0, NULL);
5316     ok (hparent != 0, "Failed to create parent window\n");
5317 
5318     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5319                              0, 0, 10, 10, hparent, 0, 0, NULL);
5320     ok (hchild != 0, "Failed to create child window\n");
5321     flush_sequence();
5322     SetWindowPos(hparent, NULL, 0, 0, 100, 100, SWP_SHOWWINDOW);
5323     ok_sequence(WmFirstDrawChildSeq2, /* Expect child to be redrawn */
5324                 "SetWindowPos:show_popup_first_show_window_child2", FALSE);
5325     DestroyWindow(hchild);
5326     DestroyWindow(hparent);
5327 
5328     /* Test message sequence for extreme position and size */
5329 
5330     flush_sequence();
5331     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5332                              -10, -10, 10000, 10000, NULL, 0, 0, NULL );
5333     ok (hwnd != 0, "Failed to create popup window\n");
5334     ok_sequence(WmShowPopupExtremeLocationSeq, "RedrawWindow:show_popup_extreme_location", FALSE);
5335     DestroyWindow(hwnd);
5336 
5337 
5338     /* Test child windows */
5339 
5340     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5341                               100, 100, 200, 200, 0, 0, 0, NULL);
5342     ok (hparent != 0, "Failed to create parent window\n");
5343     flush_sequence();
5344 
5345     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
5346                              0, 0, 10, 10, hparent, 0, 0, NULL);
5347     ok (hchild != 0, "Failed to create child window\n");
5348     ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
5349     DestroyWindow(hchild);
5350     flush_sequence();
5351 
5352     /* visible child window with a caption */
5353     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
5354                              WS_CHILD | WS_VISIBLE | WS_CAPTION,
5355                              0, 0, 10, 10, hparent, 0, 0, NULL);
5356     ok (hchild != 0, "Failed to create child window\n");
5357     ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
5358 
5359     trace("testing scroll APIs on a visible child window %p\n", hchild);
5360     test_scroll_messages(hchild);
5361 
5362     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5363     ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
5364 
5365     DestroyWindow(hchild);
5366     flush_sequence();
5367 
5368     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5369                              0, 0, 10, 10, hparent, 0, 0, NULL);
5370     ok (hchild != 0, "Failed to create child window\n");
5371     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
5372 
5373     hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
5374                                100, 100, 50, 50, hparent, 0, 0, NULL);
5375     ok (hchild2 != 0, "Failed to create child2 window\n");
5376     flush_sequence();
5377 
5378     hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
5379                               0, 100, 50, 50, hchild, 0, 0, NULL);
5380     ok (hbutton != 0, "Failed to create button window\n");
5381 
5382     /* test WM_SETREDRAW on a not visible child window */
5383     test_WM_SETREDRAW(hchild);
5384 
5385     ShowWindow(hchild, SW_SHOW);
5386     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5387 
5388     /* check parent messages too */
5389     log_all_parent_messages++;
5390     ShowWindow(hchild, SW_HIDE);
5391     ok_sequence(WmHideChildSeq2, "ShowWindow(SW_HIDE):child", FALSE);
5392     log_all_parent_messages--;
5393 
5394     ShowWindow(hchild, SW_SHOW);
5395     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5396 
5397     ShowWindow(hchild, SW_HIDE);
5398     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
5399 
5400     ShowWindow(hchild, SW_SHOW);
5401     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5402 
5403     /* test WM_SETREDRAW on a visible child window */
5404     test_WM_SETREDRAW(hchild);
5405 
5406     log_all_parent_messages++;
5407     MoveWindow(hchild, 10, 10, 20, 20, TRUE);
5408     ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
5409     log_all_parent_messages--;
5410 
5411     ShowWindow(hchild, SW_HIDE);
5412     flush_sequence();
5413     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5414     ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
5415 
5416     ShowWindow(hchild, SW_HIDE);
5417     flush_sequence();
5418     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
5419     ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
5420 
5421     /* DestroyWindow sequence below expects that a child has focus */
5422     SetFocus(hchild);
5423     flush_sequence();
5424 
5425     DestroyWindow(hchild);
5426     ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
5427     DestroyWindow(hchild2);
5428     DestroyWindow(hbutton);
5429 
5430     flush_sequence();
5431     hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
5432                              0, 0, 100, 100, hparent, 0, 0, NULL);
5433     ok (hchild != 0, "Failed to create child popup window\n");
5434     ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
5435     DestroyWindow(hchild);
5436 
5437     /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
5438     flush_sequence();
5439     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
5440                              0, 0, 100, 100, hparent, 0, 0, NULL);
5441     ok (hchild != 0, "Failed to create popup window\n");
5442     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
5443     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5444     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
5445     flush_sequence();
5446     ShowWindow(hchild, SW_SHOW);
5447     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
5448     flush_sequence();
5449     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5450     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
5451     flush_sequence();
5452     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5453     ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
5454     DestroyWindow(hchild);
5455 
5456     /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
5457      * changes nothing in message sequences.
5458      */
5459     flush_sequence();
5460     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5461                              0, 0, 100, 100, hparent, 0, 0, NULL);
5462     ok (hchild != 0, "Failed to create popup window\n");
5463     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
5464     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5465     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
5466     flush_sequence();
5467     ShowWindow(hchild, SW_SHOW);
5468     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
5469     flush_sequence();
5470     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5471     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
5472     DestroyWindow(hchild);
5473 
5474     flush_sequence();
5475     hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
5476                            0, 0, 100, 100, hparent, 0, 0, NULL);
5477     ok(hwnd != 0, "Failed to create custom dialog window\n");
5478     ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
5479 
5480     if(0) {
5481     trace("testing scroll APIs on a visible dialog %p\n", hwnd);
5482     test_scroll_messages(hwnd);
5483     }
5484 
5485     flush_sequence();
5486 
5487     test_def_id = TRUE;
5488     SendMessageA(hwnd, WM_NULL, 0, 0);
5489 
5490     flush_sequence();
5491     after_end_dialog = TRUE;
5492     EndDialog( hwnd, 0 );
5493     ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
5494 
5495     DestroyWindow(hwnd);
5496     after_end_dialog = FALSE;
5497     test_def_id = FALSE;
5498 
5499     ok(GetCursorPos(&pos), "GetCursorPos failed\n");
5500     ok(SetCursorPos(109, 109), "SetCursorPos failed\n");
5501 
5502     hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP|WS_CHILD,
5503                            0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
5504     ok(hwnd != 0, "Failed to create custom dialog window\n");
5505     flush_sequence();
5506     trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
5507     ShowWindow(hwnd, SW_SHOW);
5508     ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
5509 
5510     flush_events();
5511     flush_sequence();
5512     ret = DrawMenuBar(hwnd);
5513     ok(ret, "DrawMenuBar failed: %d\n", GetLastError());
5514     flush_events();
5515     ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
5516     ok(SetCursorPos(pos.x, pos.y), "SetCursorPos failed\n");
5517 
5518     DestroyWindow(hwnd);
5519 
5520     hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_CHILD|WS_VISIBLE,
5521             0, 0, 100, 100, hparent, 0, GetModuleHandleA(0), NULL);
5522     ok(hwnd != 0, "Failed to create custom dialog window\n");
5523     flush_events();
5524     flush_sequence();
5525     ret = DrawMenuBar(hwnd);
5526     ok(ret, "DrawMenuBar failed: %d\n", GetLastError());
5527     flush_events();
5528     ok_sequence(WmEmptySeq, "DrawMenuBar for a child window", FALSE);
5529 
5530     DestroyWindow(hwnd);
5531 
5532     flush_sequence();
5533     DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
5534     ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
5535 
5536     DestroyWindow(hparent);
5537     flush_sequence();
5538 
5539     /* Message sequence for SetMenu */
5540     ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a destroyed window\n");
5541     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "last error is %d\n", GetLastError());
5542     ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
5543 
5544     hmenu = CreateMenu();
5545     ok (hmenu != 0, "Failed to create menu\n");
5546     ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
5547     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5548                            100, 100, 200, 200, 0, hmenu, 0, NULL);
5549     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
5550     ok (SetMenu(hwnd, 0), "SetMenu\n");
5551     ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
5552     ok (SetMenu(hwnd, 0), "SetMenu\n");
5553     ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
5554     ShowWindow(hwnd, SW_SHOW);
5555     UpdateWindow( hwnd );
5556     flush_events();
5557     flush_sequence();
5558     ok (SetMenu(hwnd, 0), "SetMenu\n");
5559     ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
5560     ok (SetMenu(hwnd, hmenu), "SetMenu\n");
5561     ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
5562 
5563     UpdateWindow( hwnd );
5564     flush_events();
5565     flush_sequence();
5566     ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
5567     flush_events();
5568     ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
5569 
5570     DestroyWindow(hwnd);
5571     flush_sequence();
5572 
5573     /* Message sequence for EnableWindow */
5574     hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5575                               100, 100, 200, 200, 0, 0, 0, NULL);
5576     ok (hparent != 0, "Failed to create parent window\n");
5577     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5578                              0, 0, 10, 10, hparent, 0, 0, NULL);
5579     ok (hchild != 0, "Failed to create child window\n");
5580 
5581     SetFocus(hchild);
5582     flush_events();
5583     flush_sequence();
5584 
5585     EnableWindow(hparent, FALSE);
5586     ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
5587 
5588     EnableWindow(hparent, FALSE);
5589     ok_sequence(WmEnableWindowSeq_2, "EnableWindow(FALSE)", FALSE);
5590 
5591     EnableWindow(hparent, TRUE);
5592     ok_sequence(WmEnableWindowSeq_3, "EnableWindow(TRUE)", FALSE);
5593 
5594     EnableWindow(hparent, TRUE);
5595     ok_sequence(WmEnableWindowSeq_4, "EnableWindow(TRUE)", FALSE);
5596 
5597     flush_events();
5598     flush_sequence();
5599 
5600     test_MsgWaitForMultipleObjects(hparent);
5601     test_WM_DEVICECHANGE(hparent);
5602 
5603     /* the following test causes an exception in user.exe under win9x */
5604     if (!PostMessageW( hparent, WM_USER, 0, 0 ))
5605     {
5606         DestroyWindow(hparent);
5607         flush_sequence();
5608         return;
5609     }
5610     PostMessageW( hparent, WM_USER+1, 0, 0 );
5611     /* PeekMessage(NULL) fails, but still removes the message */
5612     SetLastError(0xdeadbeef);
5613     ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
5614     ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
5615         GetLastError() == 0xdeadbeef, /* NT4 */
5616         "last error is %d\n", GetLastError() );
5617     ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
5618     ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
5619 
5620     DestroyWindow(hchild);
5621     DestroyWindow(hparent);
5622     flush_sequence();
5623 
5624     /* Message sequences for WM_SETICON */
5625     trace("testing WM_SETICON\n");
5626     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
5627                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5628                            NULL, NULL, 0);
5629     ShowWindow(hwnd, SW_SHOW);
5630     UpdateWindow(hwnd);
5631     flush_events();
5632     flush_sequence();
5633     SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5634     ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
5635 
5636     ShowWindow(hwnd, SW_HIDE);
5637     flush_events();
5638     flush_sequence();
5639     SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5640     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window with caption", FALSE);
5641     DestroyWindow(hwnd);
5642     flush_sequence();
5643 
5644     hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
5645                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5646                            NULL, NULL, 0);
5647     ShowWindow(hwnd, SW_SHOW);
5648     UpdateWindow(hwnd);
5649     flush_events();
5650     flush_sequence();
5651     SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5652     ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
5653 
5654     ShowWindow(hwnd, SW_HIDE);
5655     flush_events();
5656     flush_sequence();
5657     SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5658     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
5659 
5660     flush_sequence();
5661     res = SendMessageA(hwnd, 0x3B, 0x8000000b, 0);
5662     if (!res)
5663     {
5664         todo_wine win_skip( "Message 0x3b not supported\n" );
5665         goto done;
5666     }
5667     ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE);
5668     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %ld\n", res);
5669     res = SendMessageA(hwnd, 0x3B, 0x0000000b, 0);
5670     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE);
5671     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %ld\n", res);
5672     res = SendMessageA(hwnd, 0x3B, 0x0000000f, 0);
5673     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE);
5674     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %ld\n", res);
5675 
5676     flush_sequence();
5677     res = SendMessageA(hwnd, 0x3B, 0x80000008, 0);
5678     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE);
5679     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %ld\n", res);
5680     res = SendMessageA(hwnd, 0x3B, 0x00000008, 0);
5681     ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE);
5682     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %ld\n", res);
5683 
5684     res = SendMessageA(hwnd, 0x3B, 0x80000004, 0);
5685     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE);
5686     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %ld\n", res);
5687 
5688     res = SendMessageA(hwnd, 0x3B, 0x80000001, 0);
5689     ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE);
5690     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %ld\n", res);
5691 
5692 done:
5693     DestroyWindow(hwnd);
5694     flush_sequence();
5695 }
5696 
5697 static void test_setwindowpos(void)
5698 {
5699     HWND hwnd;
5700     RECT rc;
5701     LRESULT res;
5702     const INT winX = 100;
5703     const INT winY = 100;
5704     const INT sysX = GetSystemMetrics(SM_CXMINTRACK);
5705 
5706     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
5707                            0, 0, winX, winY, 0,
5708                            NULL, NULL, 0);
5709 
5710     GetWindowRect(hwnd, &rc);
5711     expect(sysX, rc.right);
5712     expect(winY, rc.bottom);
5713 
5714     flush_events();
5715     flush_sequence();
5716     res = SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, winX, winY, 0);
5717     ok_sequence(WmZOrder, "Z-Order", TRUE);
5718     ok(res == TRUE, "SetWindowPos expected TRUE, got %ld\n", res);
5719 
5720     GetWindowRect(hwnd, &rc);
5721     expect(sysX, rc.right);
5722     expect(winY, rc.bottom);
5723     DestroyWindow(hwnd);
5724 }
5725 
5726 static void invisible_parent_tests(void)
5727 {
5728     HWND hparent, hchild;
5729 
5730     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
5731                               100, 100, 200, 200, 0, 0, 0, NULL);
5732     ok (hparent != 0, "Failed to create parent window\n");
5733     flush_sequence();
5734 
5735     /* test showing child with hidden parent */
5736 
5737     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5738                              0, 0, 10, 10, hparent, 0, 0, NULL);
5739     ok (hchild != 0, "Failed to create child window\n");
5740     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
5741 
5742     ShowWindow( hchild, SW_MINIMIZE );
5743     ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
5744     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5745     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5746 
5747     /* repeat */
5748     flush_events();
5749     flush_sequence();
5750     ShowWindow( hchild, SW_MINIMIZE );
5751     ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
5752 
5753     DestroyWindow(hchild);
5754     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5755                              0, 0, 10, 10, hparent, 0, 0, NULL);
5756     flush_sequence();
5757 
5758     ShowWindow( hchild, SW_MAXIMIZE );
5759     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
5760     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5761     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5762 
5763     /* repeat */
5764     flush_events();
5765     flush_sequence();
5766     ShowWindow( hchild, SW_MAXIMIZE );
5767     ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
5768 
5769     DestroyWindow(hchild);
5770     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5771                              0, 0, 10, 10, hparent, 0, 0, NULL);
5772     flush_sequence();
5773 
5774     ShowWindow( hchild, SW_RESTORE );
5775     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
5776     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5777     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5778 
5779     DestroyWindow(hchild);
5780     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5781                              0, 0, 10, 10, hparent, 0, 0, NULL);
5782     flush_sequence();
5783 
5784     ShowWindow( hchild, SW_SHOWMINIMIZED );
5785     ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
5786     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5787     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5788 
5789     /* repeat */
5790     flush_events();
5791     flush_sequence();
5792     ShowWindow( hchild, SW_SHOWMINIMIZED );
5793     ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
5794 
5795     DestroyWindow(hchild);
5796     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5797                              0, 0, 10, 10, hparent, 0, 0, NULL);
5798     flush_sequence();
5799 
5800     /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
5801     ShowWindow( hchild, SW_SHOWMAXIMIZED );
5802     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
5803     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5804     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5805 
5806     DestroyWindow(hchild);
5807     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5808                              0, 0, 10, 10, hparent, 0, 0, NULL);
5809     flush_sequence();
5810 
5811     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5812     ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5813     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5814     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5815 
5816     /* repeat */
5817     flush_events();
5818     flush_sequence();
5819     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5820     ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5821 
5822     DestroyWindow(hchild);
5823     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5824                              0, 0, 10, 10, hparent, 0, 0, NULL);
5825     flush_sequence();
5826 
5827     /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
5828     ShowWindow( hchild, SW_FORCEMINIMIZE );
5829     ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
5830 todo_wine {
5831     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5832 }
5833     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5834 
5835     DestroyWindow(hchild);
5836     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5837                              0, 0, 10, 10, hparent, 0, 0, NULL);
5838     flush_sequence();
5839 
5840     ShowWindow( hchild, SW_SHOWNA );
5841     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5842     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5843     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5844 
5845     /* repeat */
5846     flush_events();
5847     flush_sequence();
5848     ShowWindow( hchild, SW_SHOWNA );
5849     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5850 
5851     DestroyWindow(hchild);
5852     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5853                              0, 0, 10, 10, hparent, 0, 0, NULL);
5854     flush_sequence();
5855 
5856     ShowWindow( hchild, SW_SHOW );
5857     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5858     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5859     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5860 
5861     /* repeat */
5862     flush_events();
5863     flush_sequence();
5864     ShowWindow( hchild, SW_SHOW );
5865     ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5866 
5867     ShowWindow( hchild, SW_HIDE );
5868     ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
5869     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5870     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5871 
5872     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5873     ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
5874     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5875     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5876 
5877     SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5878     ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
5879     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
5880     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5881 
5882     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5883     flush_sequence();
5884     DestroyWindow(hchild);
5885     ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
5886 
5887     DestroyWindow(hparent);
5888     flush_sequence();
5889 }
5890 
5891 /****************** button message test *************************/
5892 #define ID_BUTTON 0x000e
5893 
5894 static const struct message WmSetFocusButtonSeq[] =
5895 {
5896     { HCBT_SETFOCUS, hook },
5897     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5898     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5899     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5900     { WM_SETFOCUS, sent|wparam, 0 },
5901     { WM_CTLCOLORBTN, sent|parent },
5902     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5903     { WM_APP, sent|wparam|lparam, 0, 0 },
5904     { 0 }
5905 };
5906 static const struct message WmKillFocusButtonSeq[] =
5907 {
5908     { HCBT_SETFOCUS, hook },
5909     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5910     { WM_KILLFOCUS, sent|wparam, 0 },
5911     { WM_CTLCOLORBTN, sent|parent },
5912     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5913     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5914     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5915     { WM_APP, sent|wparam|lparam, 0, 0 },
5916     { WM_PAINT, sent },
5917     { WM_CTLCOLORBTN, sent|parent },
5918     { 0 }
5919 };
5920 static const struct message WmSetFocusStaticSeq[] =
5921 {
5922     { HCBT_SETFOCUS, hook },
5923     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5924     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5925     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5926     { WM_SETFOCUS, sent|wparam, 0 },
5927     { WM_CTLCOLORSTATIC, sent|parent },
5928     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5929     { WM_COMMAND, sent|wparam|parent|optional, MAKEWPARAM(ID_BUTTON, BN_CLICKED) }, /* radio button */
5930     { WM_APP, sent|wparam|lparam, 0, 0 },
5931     { 0 }
5932 };
5933 static const struct message WmKillFocusStaticSeq[] =
5934 {
5935     { HCBT_SETFOCUS, hook },
5936     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5937     { WM_KILLFOCUS, sent|wparam, 0 },
5938     { WM_CTLCOLORSTATIC, sent|parent },
5939     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5940     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5941     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5942     { WM_APP, sent|wparam|lparam, 0, 0 },
5943     { WM_PAINT, sent },
5944     { WM_CTLCOLORSTATIC, sent|parent },
5945     { 0 }
5946 };
5947 static const struct message WmSetFocusOwnerdrawSeq[] =
5948 {
5949     { HCBT_SETFOCUS, hook },
5950     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5951     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5952     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5953     { WM_SETFOCUS, sent|wparam, 0 },
5954     { WM_CTLCOLORBTN, sent|parent },
5955     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x001040e4 },
5956     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5957     { WM_APP, sent|wparam|lparam, 0, 0 },
5958     { 0 }
5959 };
5960 static const struct message WmKillFocusOwnerdrawSeq[] =
5961 {
5962     { HCBT_SETFOCUS, hook },
5963     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5964     { WM_KILLFOCUS, sent|wparam, 0 },
5965     { WM_CTLCOLORBTN, sent|parent },
5966     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000040e4 },
5967     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5968     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5969     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5970     { WM_APP, sent|wparam|lparam, 0, 0 },
5971     { WM_PAINT, sent },
5972     { WM_CTLCOLORBTN, sent|parent },
5973     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
5974     { 0 }
5975 };
5976 static const struct message WmLButtonDownSeq[] =
5977 {
5978     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
5979     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5980     { HCBT_SETFOCUS, hook },
5981     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
5982     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5983     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5984     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
5985     { WM_CTLCOLORBTN, sent|defwinproc },
5986     { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
5987     { WM_CTLCOLORBTN, sent|defwinproc },
5988     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5989     { 0 }
5990 };
5991 static const struct message WmLButtonDownStaticSeq[] =
5992 {
5993     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
5994     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5995     { HCBT_SETFOCUS, hook },
5996     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
5997     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5998     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5999     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
6000     { WM_CTLCOLORSTATIC, sent|defwinproc },
6001     { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
6002     { WM_CTLCOLORSTATIC, sent|defwinproc },
6003     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6004     { 0 }
6005 };
6006 static const struct message WmLButtonUpSeq[] =
6007 {
6008     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6009     { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6010     { WM_CTLCOLORBTN, sent|defwinproc },
6011     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6012     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6013     { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6014     { 0 }
6015 };
6016 static const struct message WmLButtonUpStaticSeq[] =
6017 {
6018     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6019     { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6020     { WM_CTLCOLORSTATIC, sent|defwinproc },
6021     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6022     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6023     { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6024     { 0 }
6025 };
6026 static const struct message WmLButtonUpAutoSeq[] =
6027 {
6028     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6029     { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6030     { WM_CTLCOLORSTATIC, sent|defwinproc },
6031     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6032     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6033     { BM_SETCHECK, sent|defwinproc },
6034     { WM_CTLCOLORSTATIC, sent|defwinproc, 0, 0 },
6035     { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6036     { 0 }
6037 };
6038 static const struct message WmLButtonUpBrokenSeq[] =
6039 {
6040     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6041     { 0 }
6042 };
6043 static const struct message WmSetFontButtonSeq[] =
6044 {
6045     { WM_SETFONT, sent },
6046     { WM_PAINT, sent },
6047     { WM_ERASEBKGND, sent|defwinproc|optional },
6048     { WM_CTLCOLORBTN, sent|defwinproc },
6049     { WM_CTLCOLORBTN, sent|defwinproc|optional }, /* FIXME: Wine sends it twice for BS_OWNERDRAW */
6050     { 0 }
6051 };
6052 static const struct message WmSetFontStaticSeq[] =
6053 {
6054     { WM_SETFONT, sent },
6055     { WM_PAINT, sent },
6056     { WM_ERASEBKGND, sent|defwinproc|optional },
6057     { WM_CTLCOLORSTATIC, sent|defwinproc },
6058     { 0 }
6059 };
6060 static const struct message WmSetTextButtonSeq[] =
6061 {
6062     { WM_SETTEXT, sent },
6063     { WM_CTLCOLORBTN, sent|parent },
6064     { WM_CTLCOLORBTN, sent|parent },
6065     { WM_COMMAND, sent|parent|optional },
6066     { WM_DRAWITEM, sent|parent|optional },
6067     { 0 }
6068 };
6069 static const struct message WmSetTextStaticSeq[] =
6070 {
6071     { WM_SETTEXT, sent },
6072     { WM_CTLCOLORSTATIC, sent|parent },
6073     { WM_CTLCOLORSTATIC, sent|parent },
6074     { 0 }
6075 };
6076 static const struct message WmSetTextGroupSeq[] =
6077 {
6078     { WM_SETTEXT, sent },
6079     { WM_CTLCOLORSTATIC, sent|parent },
6080     { WM_CTLCOLORSTATIC, sent|parent|optional }, /* FIXME: Missing in Wine */
6081     { WM_CTLCOLORSTATIC, sent|parent|optional }, /* FIXME: Missing in Wine */
6082     { 0 }
6083 };
6084 static const struct message WmSetTextInvisibleSeq[] =
6085 {
6086     { WM_SETTEXT, sent },
6087     { 0 }
6088 };
6089 static const struct message WmSetStyleButtonSeq[] =
6090 {
6091     { BM_SETSTYLE, sent },
6092     { WM_APP, sent|wparam|lparam, 0, 0 },
6093     { WM_PAINT, sent },
6094     { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6095     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6096     { WM_CTLCOLORBTN, sent|parent },
6097     { 0 }
6098 };
6099 static const struct message WmSetStyleStaticSeq[] =
6100 {
6101     { BM_SETSTYLE, sent },
6102     { WM_APP, sent|wparam|lparam, 0, 0 },
6103     { WM_PAINT, sent },
6104     { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6105     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6106     { WM_CTLCOLORSTATIC, sent|parent },
6107     { 0 }
6108 };
6109 static const struct message WmSetStyleUserSeq[] =
6110 {
6111     { BM_SETSTYLE, sent },
6112     { WM_APP, sent|wparam|lparam, 0, 0 },
6113     { WM_PAINT, sent },
6114     { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6115     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6116     { WM_CTLCOLORBTN, sent|parent },
6117     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_PAINT) },
6118     { 0 }
6119 };
6120 static const struct message WmSetStyleOwnerdrawSeq[] =
6121 {
6122     { BM_SETSTYLE, sent },
6123     { WM_APP, sent|wparam|lparam, 0, 0 },
6124     { WM_PAINT, sent },
6125     { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
6126     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6127     { WM_CTLCOLORBTN, sent|parent },
6128     { WM_CTLCOLORBTN, sent|parent|optional }, /* Win9x doesn't send it */
6129     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
6130     { 0 }
6131 };
6132 static const struct message WmSetStateButtonSeq[] =
6133 {
6134     { BM_SETSTATE, sent },
6135     { WM_CTLCOLORBTN, sent|parent },
6136     { WM_APP, sent|wparam|lparam, 0, 0 },
6137     { 0 }
6138 };
6139 static const struct message WmSetStateStaticSeq[] =
6140 {
6141     { BM_SETSTATE, sent },
6142     { WM_CTLCOLORSTATIC, sent|parent },
6143     { WM_APP, sent|wparam|lparam, 0, 0 },
6144     { 0 }
6145 };
6146 static const struct message WmSetStateUserSeq[] =
6147 {
6148     { BM_SETSTATE, sent },
6149     { WM_CTLCOLORBTN, sent|parent },
6150     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_HILITE) },
6151     { WM_APP, sent|wparam|lparam, 0, 0 },
6152     { 0 }
6153 };
6154 static const struct message WmSetStateOwnerdrawSeq[] =
6155 {
6156     { BM_SETSTATE, sent },
6157     { WM_CTLCOLORBTN, sent|parent },
6158     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000120e4 },
6159     { WM_APP, sent|wparam|lparam, 0, 0 },
6160     { 0 }
6161 };
6162 static const struct message WmClearStateButtonSeq[] =
6163 {
6164     { BM_SETSTATE, sent },
6165     { WM_CTLCOLORBTN, sent|parent },
6166     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_UNHILITE) },
6167     { WM_APP, sent|wparam|lparam, 0, 0 },
6168     { 0 }
6169 };
6170 static const struct message WmDisableButtonSeq[] =
6171 {
6172     { WM_LBUTTONDOWN, sent },
6173     { BM_SETSTATE, sent|defwinproc },
6174     { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6175     { WM_CTLCOLORBTN, sent|optional },
6176     { WM_LBUTTONUP, sent },
6177     { BM_SETSTATE, sent|defwinproc },
6178     { WM_CTLCOLORBTN, sent|defwinproc|optional },
6179     { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6180     { BM_SETCHECK, sent|defwinproc|optional },
6181     { WM_CTLCOLORBTN, sent|optional },
6182     { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6183     { WM_CAPTURECHANGED, sent|defwinproc },
6184     { WM_COMMAND, sent },
6185     { 0 }
6186 };
6187 static const struct message WmClearStateOwnerdrawSeq[] =
6188 {
6189     { BM_SETSTATE, sent },
6190     { WM_CTLCOLORBTN, sent|parent },
6191     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000020e4 },
6192     { WM_APP, sent|wparam|lparam, 0, 0 },
6193     { 0 }
6194 };
6195 static const struct message WmSetCheckIgnoredSeq[] =
6196 {
6197     { BM_SETCHECK, sent },
6198     { WM_APP, sent|wparam|lparam, 0, 0 },
6199     { 0 }
6200 };
6201 static const struct message WmSetCheckStaticSeq[] =
6202 {
6203     { BM_SETCHECK, sent },
6204     { WM_CTLCOLORSTATIC, sent|parent },
6205     { WM_APP, sent|wparam|lparam, 0, 0 },
6206     { 0 }
6207 };
6208 
6209 static WNDPROC old_button_proc;
6210 
6211 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6212 {
6213     static LONG defwndproc_counter = 0;
6214     LRESULT ret;
6215     struct recvd_message msg;
6216 
6217     if (ignore_message( message )) return 0;
6218 
6219     switch (message)
6220     {
6221     case WM_SYNCPAINT:
6222         break;
6223     case BM_SETSTATE:
6224         if (GetCapture())
6225             ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
6226 
6227         lParam = (ULONG_PTR)GetMenu(hwnd);
6228         goto log_it;
6229 
6230     case WM_GETDLGCODE:
6231         if (lParam)
6232         {
6233             MSG *msg = (MSG *)lParam;
6234             lParam = MAKELPARAM(msg->message, msg->wParam);
6235         }
6236         wParam = (ULONG_PTR)GetMenu(hwnd);
6237         goto log_it;
6238 
6239     case BM_SETCHECK:
6240     case BM_GETCHECK:
6241         lParam = (ULONG_PTR)GetMenu(hwnd);
6242         /* fall through */
6243 log_it:
6244     default:
6245         msg.hwnd = hwnd;
6246         msg.message = message;
6247         msg.flags = sent|wparam|lparam;
6248         if (defwndproc_counter) msg.flags |= defwinproc;
6249         msg.wParam = wParam;
6250         msg.lParam = lParam;
6251         msg.descr = "button";
6252         add_message(&msg);
6253     }
6254 
6255     defwndproc_counter++;
6256     ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
6257     defwndproc_counter--;
6258 
6259     return ret;
6260 }
6261 
6262 static void subclass_button(void)
6263 {
6264     WNDCLASSA cls;
6265 
6266     if (!GetClassInfoA(0, "button", &cls)) assert(0);
6267 
6268     old_button_proc = cls.lpfnWndProc;
6269 
6270     cls.hInstance = GetModuleHandleA(NULL);
6271     cls.lpfnWndProc = button_hook_proc;
6272     cls.lpszClassName = "my_button_class";
6273     UnregisterClassA(cls.lpszClassName, cls.hInstance);
6274     if (!RegisterClassA(&cls)) assert(0);
6275 }
6276 
6277 static void test_button_messages(void)
6278 {
6279     static const struct
6280     {
6281         DWORD style;
6282         DWORD dlg_code;
6283         const struct message *setfocus;
6284         const struct message *killfocus;
6285         const struct message *setstyle;
6286         const struct message *setstate;
6287         const struct message *clearstate;
6288         const struct message *setcheck;
6289         const struct message *lbuttondown;
6290         const struct message *lbuttonup;
6291         const struct message *setfont;
6292         const struct message *settext;
6293     } button[] = {
6294         { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
6295           WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
6296           WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq,
6297           WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6298           WmSetTextButtonSeq },
6299         { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
6300           WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
6301           WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq,
6302           WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6303           WmSetTextButtonSeq },
6304         { BS_CHECKBOX, DLGC_BUTTON,
6305           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6306           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6307           WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6308           WmSetTextStaticSeq },
6309         { BS_AUTOCHECKBOX, DLGC_BUTTON,
6310           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6311           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6312           WmLButtonDownStaticSeq, WmLButtonUpAutoSeq, WmSetFontStaticSeq,
6313           WmSetTextStaticSeq },
6314         { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
6315           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6316           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6317           WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6318           WmSetTextStaticSeq },
6319         { BS_3STATE, DLGC_BUTTON,
6320           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6321           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6322           WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6323           WmSetTextStaticSeq },
6324         { BS_AUTO3STATE, DLGC_BUTTON,
6325           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6326           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6327           WmLButtonDownStaticSeq, WmLButtonUpAutoSeq, WmSetFontStaticSeq,
6328           WmSetTextStaticSeq },
6329         { BS_GROUPBOX, DLGC_STATIC,
6330           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6331           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckIgnoredSeq,
6332           WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6333           WmSetTextGroupSeq },
6334         { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
6335           WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleUserSeq,
6336           WmSetStateUserSeq, WmClearStateButtonSeq, WmSetCheckIgnoredSeq,
6337           WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6338           WmSetTextButtonSeq },
6339         { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
6340           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6341           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6342           NULL /* avoid infinite loop */, WmLButtonUpBrokenSeq, WmSetFontStaticSeq,
6343           WmSetTextStaticSeq },
6344         { BS_OWNERDRAW, DLGC_BUTTON,
6345           WmSetFocusOwnerdrawSeq, WmKillFocusOwnerdrawSeq, WmSetStyleOwnerdrawSeq,
6346           WmSetStateOwnerdrawSeq, WmClearStateOwnerdrawSeq, WmSetCheckIgnoredSeq,
6347           WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6348           WmSetTextButtonSeq },
6349     };
6350     LOGFONTA logfont = { 0 };
6351     HFONT zfont, hfont2;
6352     unsigned int i;
6353     HWND hwnd, parent;
6354     DWORD dlg_code;
6355 
6356     /* selection with VK_SPACE should capture button window */
6357     hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP,
6358                            0, 0, 50, 14, 0, 0, 0, NULL);
6359     ok(hwnd != 0, "Failed to create button window\n");
6360     ReleaseCapture();
6361     SetFocus(hwnd);
6362     SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
6363     ok(GetCapture() == hwnd, "Should be captured on VK_SPACE WM_KEYDOWN\n");
6364     SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
6365     DestroyWindow(hwnd);
6366 
6367     subclass_button();
6368 
6369     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6370                              100, 100, 200, 200, 0, 0, 0, NULL);
6371     ok(parent != 0, "Failed to create parent window\n");
6372 
6373     memset(&logfont, 0, sizeof(logfont));
6374     logfont.lfHeight = -12;
6375     logfont.lfWeight = FW_NORMAL;
6376     strcpy(logfont.lfFaceName, "Tahoma");
6377 
6378     hfont2 = CreateFontIndirectA(&logfont);
6379     ok(hfont2 != NULL, "Failed to create Tahoma font\n");
6380 
6381     for (i = 0; i < ARRAY_SIZE(button); i++)
6382     {
6383         MSG msg;
6384         DWORD style, state;
6385         HFONT prevfont;
6386         char desc[64];
6387         HDC hdc;
6388 
6389         trace("button style %08x\n", button[i].style);
6390 
6391         hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_CHILD | BS_NOTIFY,
6392                                0, 0, 50, 14, parent, (HMENU)ID_BUTTON, 0, NULL);
6393         ok(hwnd != 0, "Failed to create button window\n");
6394 
6395         style = GetWindowLongA(hwnd, GWL_STYLE);
6396         style &= ~(WS_CHILD | BS_NOTIFY);
6397         /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
6398         if (button[i].style == BS_USERBUTTON)
6399             ok(style == BS_PUSHBUTTON, "expected style BS_PUSHBUTTON got %x\n", style);
6400         else
6401             ok(style == button[i].style, "expected style %x got %x\n", button[i].style, style);
6402 
6403         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
6404         ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
6405 
6406         ShowWindow(hwnd, SW_SHOW);
6407         UpdateWindow(hwnd);
6408         SetFocus(0);
6409         flush_events();
6410         SetFocus(0);
6411         flush_sequence();
6412 
6413         log_all_parent_messages++;
6414 
6415         ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
6416         SetFocus(hwnd);
6417         SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6418         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6419         ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
6420 
6421         SetFocus(0);
6422         SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6423         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6424         ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
6425 
6426         ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
6427 
6428         SendMessageA(hwnd, BM_SETSTYLE, button[i].style | BS_BOTTOM, TRUE);
6429         SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6430         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6431         ok_sequence(button[i].setstyle, "BM_SETSTYLE on a button", FALSE);
6432 
6433         style = GetWindowLongA(hwnd, GWL_STYLE);
6434         style &= ~(WS_VISIBLE | WS_CHILD | BS_NOTIFY);
6435         /* XP doesn't turn a BS_USERBUTTON into BS_PUSHBUTTON here! */
6436         ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6437 
6438         state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6439         ok(state == 0, "expected state 0, got %04x\n", state);
6440 
6441         flush_sequence();
6442 
6443         SendMessageA(hwnd, BM_SETSTATE, TRUE, 0);
6444         SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6445         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6446         ok_sequence(button[i].setstate, "BM_SETSTATE/TRUE on a button", FALSE);
6447 
6448         state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6449         ok(state == 0x0004, "expected state 0x0004, got %04x\n", state);
6450 
6451         style = GetWindowLongA(hwnd, GWL_STYLE);
6452         style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6453         ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6454 
6455         flush_sequence();
6456 
6457         SendMessageA(hwnd, BM_SETSTATE, FALSE, 0);
6458         SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6459         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6460         ok_sequence(button[i].clearstate, "BM_SETSTATE/FALSE on a button", FALSE);
6461 
6462         state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6463         ok(state == 0, "expected state 0, got %04x\n", state);
6464 
6465         style = GetWindowLongA(hwnd, GWL_STYLE);
6466         style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6467         ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6468 
6469         state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6470         ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
6471 
6472         flush_sequence();
6473 
6474         SendMessageA(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
6475         SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6476         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6477         ok_sequence(WmSetCheckIgnoredSeq, "BM_SETCHECK on a button", FALSE);
6478 
6479         state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6480         ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
6481 
6482         style = GetWindowLongA(hwnd, GWL_STYLE);
6483         style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6484         ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6485 
6486         flush_sequence();
6487 
6488         SendMessageA(hwnd, BM_SETCHECK, BST_CHECKED, 0);
6489         SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6490         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6491         ok_sequence(button[i].setcheck, "BM_SETCHECK on a button", FALSE);
6492 
6493         SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 1");
6494         sprintf(desc, "button[%i]: WM_SETTEXT on a visible button", i);
6495         ok_sequence(button[i].settext, desc, FALSE);
6496 
6497         ShowWindow(hwnd, SW_HIDE);
6498         flush_events();
6499         flush_sequence();
6500 
6501         SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 2");
6502         sprintf(desc, "button[%i]: WM_SETTEXT on an invisible button", i);
6503         ok_sequence(WmSetTextInvisibleSeq, desc, FALSE);
6504 
6505         ShowWindow(hwnd, SW_SHOW);
6506         ShowWindow(parent, SW_HIDE);
6507         flush_events();
6508         flush_sequence();
6509 
6510         SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 3");
6511         sprintf(desc, "button[%i]: WM_SETTEXT on an invisible button", i);
6512         ok_sequence(WmSetTextInvisibleSeq, desc, FALSE);
6513 
6514         ShowWindow(parent, SW_SHOW);
6515         flush_events();
6516 
6517         state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6518         if (button[i].style == BS_PUSHBUTTON ||
6519             button[i].style == BS_DEFPUSHBUTTON ||
6520             button[i].style == BS_GROUPBOX ||
6521             button[i].style == BS_USERBUTTON ||
6522             button[i].style == BS_OWNERDRAW)
6523             ok(state == BST_UNCHECKED, "expected check 0, got %04x\n", state);
6524         else
6525             ok(state == BST_CHECKED, "expected check 1, got %04x\n", state);
6526 
6527         style = GetWindowLongA(hwnd, GWL_STYLE);
6528         style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6529         if (button[i].style == BS_RADIOBUTTON ||
6530             button[i].style == BS_AUTORADIOBUTTON)
6531             ok(style == (button[i].style | WS_TABSTOP), "expected style %04x | WS_TABSTOP got %04x\n", button[i].style, style);
6532         else
6533             ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6534 
6535         log_all_parent_messages--;
6536 
6537         DestroyWindow(hwnd);
6538 
6539         hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP | WS_VISIBLE,
6540                                0, 0, 50, 14, 0, 0, 0, NULL);
6541         ok(hwnd != 0, "Failed to create button window\n");
6542 
6543         SetForegroundWindow(hwnd);
6544         flush_events();
6545 
6546         SetActiveWindow(hwnd);
6547         SetFocus(0);
6548         flush_sequence();
6549 
6550         if (button[i].lbuttondown)
6551         {
6552             SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
6553             sprintf(desc, "button[%i]: WM_LBUTTONDOWN on a button", i);
6554             ok_sequence(button[i].lbuttondown, desc, FALSE);
6555         }
6556 
6557         SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
6558         sprintf(desc, "button[%i]: WM_LBUTTONUP on a button", i);
6559         ok_sequence(button[i].lbuttonup, desc, FALSE);
6560 
6561         flush_sequence();
6562         zfont = GetStockObject(DEFAULT_GUI_FONT);
6563         SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
6564         UpdateWindow(hwnd);
6565         sprintf(desc, "button[%i]: WM_SETFONT on a button", i);
6566         ok_sequence(button[i].setfont, desc, FALSE);
6567 
6568         /* Test that original font is not selected back after painting */
6569         hdc = CreateCompatibleDC(0);
6570 
6571         prevfont = SelectObject(hdc, hfont2);
6572         ok(prevfont == GetStockObject(SYSTEM_FONT), "Unexpected default font\n");
6573         SendMessageA(hwnd, WM_PRINTCLIENT, (WPARAM)hdc, 0);
6574         ok(hfont2 != GetCurrentObject(hdc, OBJ_FONT), "button[%u]: unexpected font selected after WM_PRINTCLIENT\n", i);
6575         SelectObject(hdc, prevfont);
6576 
6577         prevfont = SelectObject(hdc, hfont2);
6578         ok(prevfont == GetStockObject(SYSTEM_FONT), "Unexpected default font\n");
6579         SendMessageA(hwnd, WM_PAINT, (WPARAM)hdc, 0);
6580         ok(hfont2 != GetCurrentObject(hdc, OBJ_FONT), "button[%u]: unexpected font selected after WM_PAINT\n", i);
6581         SelectObject(hdc, prevfont);
6582 
6583         DeleteDC(hdc);
6584 
6585         DestroyWindow(hwnd);
6586     }
6587 
6588     DeleteObject(hfont2);
6589     DestroyWindow(parent);
6590 
6591     /* Test if WM_LBUTTONDOWN and WM_LBUTTONUP to a disabled button leads to a WM_COMMAND for the parent */
6592 
6593     parent = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6594             100, 100, 200, 200, 0, 0, 0, NULL);
6595     ok (hwnd != 0, "Failed to create overlapped window\n");
6596 
6597     hwnd = CreateWindowExA(0, "my_button_class", "test", BS_DEFPUSHBUTTON | WS_VISIBLE | WS_CHILD,
6598                                    0, 0, 50, 14, parent, 0, 0, NULL);
6599 
6600     EnableWindow(hwnd, FALSE);
6601     flush_sequence();
6602     SendMessageA(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, 0);
6603     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
6604     ok_sequence(WmDisableButtonSeq, "Mouseclick on a disabled button", FALSE);
6605 
6606     DestroyWindow(hwnd);
6607     DestroyWindow(parent);
6608 }
6609 
6610 static void test_button_bm_get_set_image(void)
6611 {
6612     HWND hwnd;
6613     HDC hdc;
6614     HBITMAP hbmp1x1;
6615     HBITMAP hbmp2x2;
6616     HBITMAP hmask2x2;
6617     ICONINFO icon_info2x2;
6618     HICON hicon2x2;
6619     HBITMAP hbmp;
6620     HICON hicon;
6621     ICONINFO icon_info;
6622     BITMAP bm;
6623     DWORD default_style = BS_PUSHBUTTON | WS_TABSTOP | WS_POPUP | WS_VISIBLE;
6624     LRESULT ret;
6625 
6626     hdc = GetDC(0);
6627     hbmp1x1 = CreateCompatibleBitmap(hdc, 1, 1);
6628     hbmp2x2 = CreateCompatibleBitmap(hdc, 2, 2);
6629     ZeroMemory(&bm, sizeof(bm));
6630     ok(GetObjectW(hbmp1x1, sizeof(bm), &bm), "Expect GetObjectW() success\n");
6631     ok(bm.bmWidth == 1 && bm.bmHeight == 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
6632        bm.bmWidth, bm.bmHeight);
6633     ZeroMemory(&bm, sizeof(bm));
6634     ok(GetObjectW(hbmp2x2, sizeof(bm), &bm), "Expect GetObjectW() success\n");
6635     ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
6636        bm.bmWidth, bm.bmHeight);
6637 
6638     hmask2x2 = CreateCompatibleBitmap(hdc, 2, 2);
6639     ZeroMemory(&icon_info2x2, sizeof(icon_info2x2));
6640     icon_info2x2.fIcon = TRUE;
6641     icon_info2x2.hbmMask = hmask2x2;
6642     icon_info2x2.hbmColor = hbmp2x2;
6643     hicon2x2 = CreateIconIndirect(&icon_info2x2);
6644 
6645     ZeroMemory(&icon_info, sizeof(icon_info));
6646     ok(GetIconInfo(hicon2x2, &icon_info), "Expect GetIconInfo() success\n");
6647     ZeroMemory(&bm, sizeof(bm));
6648     ok(GetObjectW(icon_info.hbmColor, sizeof(bm), &bm), "Expect GetObjectW() success\n");
6649     ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
6650        bm.bmWidth, bm.bmHeight);
6651     DeleteObject(icon_info.hbmColor);
6652     DeleteObject(icon_info.hbmMask);
6653 
6654     /* Set bitmap with BS_BITMAP */
6655     hwnd = CreateWindowA("Button", "test", default_style | BS_BITMAP, 0, 0, 100, 100, 0, 0, 0, 0);
6656     ok(hwnd != NULL, "Expect hwnd not NULL\n");
6657     SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp1x1);
6658     hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_BITMAP, 0);
6659     ok(hbmp != 0, "Expect hbmp not 0\n");
6660     ZeroMemory(&bm, sizeof(bm));
6661     ok(GetObjectW(hbmp, sizeof(bm), &bm), "Expect GetObjectW() success\n");
6662     ok(bm.bmWidth == 1 && bm.bmHeight == 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
6663        bm.bmWidth, bm.bmHeight);
6664     DestroyWindow(hwnd);
6665 
6666     /* Set bitmap without BS_BITMAP */
6667     hwnd = CreateWindowA("Button", "test", default_style, 0, 0, 100, 100, 0, 0, 0, 0);
6668     ok(hwnd != NULL, "Expect hwnd not NULL\n");
6669     ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp1x1);
6670     ok(ret == 0, "Expect ret to be 0\n");
6671     hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_BITMAP, 0);
6672     ok(hbmp == NULL, "Expect hbmp to be NULL\n");
6673     DestroyWindow(hwnd);
6674 
6675     /* Set icon with BS_ICON */
6676     hwnd = CreateWindowA("Button", "test", default_style | BS_ICON, 0, 0, 100, 100, 0, 0, 0, 0);
6677     ok(hwnd != NULL, "Expect hwnd not NULL\n");
6678     SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hicon2x2);
6679     hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_ICON, 0);
6680     ok(hicon != NULL, "Expect hicon not NULL\n");
6681     ZeroMemory(&icon_info, sizeof(icon_info));
6682     ok(GetIconInfo(hicon, &icon_info), "Expect GetIconInfo() success\n");
6683     ZeroMemory(&bm, sizeof(bm));
6684     ok(GetObjectW(icon_info.hbmColor, sizeof(bm), &bm), "Expect GetObjectW() success\n");
6685     ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
6686        bm.bmWidth, bm.bmHeight);
6687     DeleteObject(icon_info.hbmColor);
6688     DeleteObject(icon_info.hbmMask);
6689     DestroyWindow(hwnd);
6690 
6691     /* Set icon without BS_ICON */
6692     hwnd = CreateWindowA("Button", "test", default_style, 0, 0, 100, 100, 0, 0, 0, 0);
6693     ok(hwnd != NULL, "Expect hwnd not NULL\n");
6694     ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hicon2x2);
6695     ok(ret == 0, "Expect ret to be 0\n");
6696     hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_ICON, 0);
6697     ok(hicon == NULL, "Expect hicon to be NULL\n");
6698     DestroyWindow(hwnd);
6699 
6700     /* Set icon with BS_BITMAP */
6701     hwnd = CreateWindowA("Button", "test", default_style | BS_BITMAP, 0, 0, 100, 100, 0, 0, 0, 0);
6702     ok(hwnd != NULL, "Expect hwnd to be not NULL\n");
6703     ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hicon2x2);
6704     ok(ret == 0, "Expect ret to be 0\n");
6705     hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_ICON, 0);
6706     ok(hicon == NULL, "Expect hicon to be NULL\n");
6707     DestroyWindow(hwnd);
6708 
6709     /* Set bitmap with BS_ICON */
6710     hwnd = CreateWindowA("Button", "test", default_style | BS_ICON, 0, 0, 100, 100, 0, 0, 0, 0);
6711     ok(hwnd != NULL, "Expect hwnd to be not NULL\n");
6712     ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp1x1);
6713     ok(ret == 0, "Expect ret to be 0\n");
6714     hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_BITMAP, 0);
6715     ok(hbmp == NULL, "Expect hbmp to be NULL\n");
6716     DestroyWindow(hwnd);
6717 
6718     DestroyIcon(hicon2x2);
6719     DeleteObject(hmask2x2);
6720     DeleteObject(hbmp2x2);
6721     DeleteObject(hbmp1x1);
6722     ReleaseDC(0, hdc);
6723 }
6724 
6725 #define ID_RADIO1 501
6726 #define ID_RADIO2 502
6727 #define ID_RADIO3 503
6728 #define ID_TEXT   504
6729 
6730 static const struct message auto_radio_button_BM_CLICK[] =
6731 {
6732     { BM_CLICK, sent|wparam|lparam, 0, 0 },
6733     { WM_LBUTTONDOWN, sent|wparam|lparam|defwinproc, 0, 0 },
6734     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6735     { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO2 },
6736     { WM_CTLCOLORSTATIC, sent|parent },
6737     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6738     { WM_LBUTTONUP, sent|wparam|lparam|defwinproc, 0, 0 },
6739     { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO2 },
6740     { WM_CTLCOLORSTATIC, sent|parent },
6741     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6742     { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO2, 0 },
6743     { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO2 },
6744     { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO1, 0 },
6745     { BM_SETCHECK, sent|wparam|lparam|defwinproc, 0, ID_RADIO1 },
6746     { WM_CTLCOLORSTATIC, sent|parent },
6747     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6748     { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO3, 0 },
6749     { BM_SETCHECK, sent|wparam|lparam|defwinproc, 0, ID_RADIO3 },
6750     { WM_CTLCOLORSTATIC, sent|parent },
6751     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6752     { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_TEXT, 0 },
6753     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6754     { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
6755     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO2, BN_CLICKED) },
6756     { WM_NCHITTEST, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6757     { WM_SETCURSOR, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6758     { WM_MOUSEMOVE, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6759     { 0 }
6760 };
6761 
6762 static const struct message auto_radio_button_VK_UP_child[] =
6763 {
6764     { WM_KEYDOWN, sent|wparam|lparam, VK_UP, 0 },
6765     { WM_KEYUP, sent|wparam|lparam, VK_UP, 0 },
6766     { 0 }
6767 };
6768 
6769 static const struct message auto_radio_button_VK_UP_parent[] =
6770 {
6771     { WM_KEYDOWN, sent|wparam|lparam|parent, VK_UP, 0 },
6772     { WM_KEYUP, sent|wparam|lparam|parent, VK_UP, 0 },
6773     { 0 }
6774 };
6775 
6776 static const struct message auto_radio_button_VK_UP_dialog[] =
6777 {
6778     { WM_GETDLGCODE, sent|parent, 0, 0 },
6779 
6780     /* optional trailer seen on some windows setups */
6781     { WM_CHANGEUISTATE, sent|optional },
6782     { WM_UPDATEUISTATE, sent|optional },
6783     { WM_UPDATEUISTATE, sent|optional },
6784     { WM_UPDATEUISTATE, sent|optional },
6785     { WM_UPDATEUISTATE, sent|optional },
6786     { WM_UPDATEUISTATE, sent|optional },
6787     { WM_UPDATEUISTATE, sent|optional },
6788     { WM_UPDATEUISTATE, sent|optional },
6789     { WM_UPDATEUISTATE, sent|optional },
6790     { WM_UPDATEUISTATE, sent|optional },
6791     { WM_UPDATEUISTATE, sent|optional },
6792     { WM_UPDATEUISTATE, sent|optional },
6793     { WM_UPDATEUISTATE, sent|optional },
6794     { WM_UPDATEUISTATE, sent|optional },
6795     { WM_UPDATEUISTATE, sent|optional },
6796     { WM_UPDATEUISTATE, sent|optional },
6797     { WM_UPDATEUISTATE, sent|optional },
6798     { WM_UPDATEUISTATE, sent|optional },
6799     { WM_UPDATEUISTATE, sent|optional },
6800     { WM_CTLCOLORSTATIC, sent|parent|optional },
6801     { WM_CTLCOLORSTATIC, sent|parent|optional },
6802     { WM_CTLCOLORSTATIC, sent|parent|optional },
6803     { WM_UPDATEUISTATE, sent|optional },
6804     { WM_CTLCOLORSTATIC, sent|parent|optional },
6805     { WM_CTLCOLORSTATIC, sent|parent|optional },
6806     { WM_UPDATEUISTATE, sent|optional },
6807     { WM_CTLCOLORBTN, sent|parent|optional },
6808     { WM_CTLCOLORBTN, sent|parent|optional },
6809     { WM_UPDATEUISTATE, sent|optional },
6810     { WM_CTLCOLORSTATIC, sent|parent|optional },
6811     { WM_CTLCOLORSTATIC, sent|parent|optional },
6812     { 0 }
6813 };
6814 
6815 static const struct message auto_radio_button_VK_DOWN_dialog[] =
6816 {
6817     { WM_GETDLGCODE, sent|parent, 0, 0 },
6818     { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, MAKELPARAM(WM_KEYDOWN, VK_DOWN) },
6819     { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
6820     { HCBT_SETFOCUS, hook },
6821     { WM_KILLFOCUS, sent, 0, 0 },
6822     { WM_CTLCOLORSTATIC, sent|parent },
6823     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO3, BN_KILLFOCUS) },
6824     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6825     { WM_SETFOCUS, sent, 0, 0 },
6826     { WM_CTLCOLORSTATIC, sent|parent },
6827     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_SETFOCUS) },
6828     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_CLICKED) },
6829     { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
6830     { WM_GETDLGCODE, sent|parent, 0, 0 },
6831     { DM_GETDEFID, sent|parent, 0, 0 },
6832     { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
6833     { BM_CLICK, sent|wparam|lparam, 1, 0 },
6834     { WM_LBUTTONDOWN, sent|wparam|lparam|defwinproc, 0, 0 },
6835     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6836     { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO1 },
6837     { WM_CTLCOLORSTATIC, sent|parent },
6838     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6839     { WM_LBUTTONUP, sent|wparam|lparam|defwinproc, 0, 0 },
6840     { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO1 },
6841     { WM_CTLCOLORSTATIC, sent|parent },
6842     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6843     { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO1, 0 },
6844     { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO1 },
6845     { WM_CTLCOLORSTATIC, sent|parent },
6846     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6847     { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO3, 0 },
6848     { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO3 },
6849     { WM_CTLCOLORSTATIC, sent|parent },
6850     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6851     { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_TEXT, 0 },
6852     { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO2, 0 },
6853     { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO2 },
6854     { WM_CTLCOLORSTATIC, sent|parent },
6855     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6856     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6857     { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
6858     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_CLICKED) },
6859     { WM_NCHITTEST, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6860     { WM_SETCURSOR, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6861     { WM_MOUSEMOVE, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6862     { WM_PAINT, sent },
6863     { WM_CTLCOLORSTATIC, sent|parent },
6864     { 0 }
6865 };
6866 
6867 static const struct message auto_radio_button_VK_DOWN_radio3[] =
6868 {
6869     { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
6870     { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO2 },
6871     { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO3 },
6872     { WM_GETDLGCODE, sent|parent, 0, 0 },
6873     { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, MAKELPARAM(WM_KEYDOWN, VK_DOWN) },
6874     { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
6875     { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
6876     { WM_GETDLGCODE, sent|wparam|lparam|parent, 0, 0 },
6877     { WM_USER, sent|parent, 0, 0 },
6878     { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
6879     { 0 }
6880 };
6881 
6882 static const struct message auto_radio_button_VK_UP_radio1[] =
6883 {
6884     { WM_GETDLGCODE, sent|parent, 0, 0 },
6885     { 0 }
6886 };
6887 
6888 static INT_PTR WINAPI radio_test_dlg_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
6889 {
6890     ParentMsgCheckProcA(hwnd, msg, wp, lp);
6891     return 1;
6892 }
6893 
6894 static void test_autoradio_BM_CLICK(void)
6895 {
6896     HWND parent, radio1, radio2, radio3;
6897     RECT rc;
6898     MSG msg;
6899     DWORD ret;
6900 
6901     subclass_button();
6902 
6903     parent = CreateDialogParamA(0, "AUTORADIO_TEST_DIALOG_1", 0, radio_test_dlg_proc, 0);
6904     ok(parent != 0, "failed to create parent window\n");
6905 
6906     radio1 = GetDlgItem(parent, ID_RADIO1);
6907     radio2 = GetDlgItem(parent, ID_RADIO2);
6908     radio3 = GetDlgItem(parent, ID_RADIO3);
6909 
6910     /* this avoids focus messages in the generated sequence */
6911     SetFocus(radio2);
6912 
6913     flush_events();
6914     flush_sequence();
6915 
6916     ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6917     ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6918     ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6919     ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6920     ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6921     ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6922 
6923     SendMessageA(radio1, BM_SETCHECK, BST_CHECKED, 0);
6924 
6925     ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6926     ok(ret == BST_CHECKED, "got %08x\n", ret);
6927     ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6928     ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6929     ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6930     ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6931 
6932     SendMessageA(radio2, BM_SETCHECK, BST_CHECKED, 0);
6933 
6934     ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6935     ok(ret == BST_CHECKED, "got %08x\n", ret);
6936     ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6937     ok(ret == BST_CHECKED, "got %08x\n", ret);
6938     ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6939     ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6940 
6941     SendMessageA(radio3, BM_SETCHECK, BST_CHECKED, 0);
6942 
6943     ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6944     ok(ret == BST_CHECKED, "got %08x\n", ret);
6945     ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6946     ok(ret == BST_CHECKED, "got %08x\n", ret);
6947     ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6948     ok(ret == BST_CHECKED, "got %08x\n", ret);
6949 
6950     GetWindowRect(radio2, &rc);
6951     SetCursorPos(rc.left+1, rc.top+1);
6952 
6953     flush_events();
6954     flush_sequence();
6955 
6956     log_all_parent_messages++;
6957 
6958     SendMessageA(radio2, BM_CLICK, 0, 0);
6959     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6960     ok_sequence(auto_radio_button_BM_CLICK, "BM_CLICK on auto-radio button", FALSE);
6961 
6962     log_all_parent_messages--;
6963 
6964     ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6965     ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6966     ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6967     ok(ret == BST_CHECKED, "got %08x\n", ret);
6968     ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6969     ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6970 
6971     DestroyWindow(parent);
6972 }
6973 
6974 #define test_radio(r1, s1, r2, s2, r3, s3) test_radio_dbg(r1, s1, r2, s2, r3, s3, __LINE__)
6975 static void test_radio_dbg(HWND radio1, int state1, HWND radio2, int state2, HWND radio3, int state3, int line)
6976 {
6977     DWORD ret;
6978 
6979     ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6980     ok_(__FILE__,line)(ret == state1 ? BST_CHECKED : BST_UNCHECKED, "got %08x\n", ret);
6981     ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6982     ok_(__FILE__,line)(ret == state2 ? BST_CHECKED : BST_UNCHECKED, "got %08x\n", ret);
6983     ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6984     ok_(__FILE__,line)(ret == state3 ? BST_CHECKED : BST_UNCHECKED, "got %08x\n", ret);
6985 }
6986 
6987 static void set_radio(HWND radio1, int state1, HWND radio2, int state2, HWND radio3, int state3)
6988 {
6989     SendMessageA(radio1, BM_SETCHECK, state1 ? BST_CHECKED : BST_UNCHECKED, 0);
6990     SendMessageA(radio2, BM_SETCHECK, state2 ? BST_CHECKED : BST_UNCHECKED, 0);
6991     SendMessageA(radio3, BM_SETCHECK, state3 ? BST_CHECKED : BST_UNCHECKED, 0);
6992 }
6993 
6994 static void test_autoradio_kbd_move(void)
6995 {
6996     HWND parent, radio1, radio2, radio3, hwnd;
6997     RECT rc;
6998     MSG msg;
6999     DWORD ret;
7000 
7001     subclass_button();
7002 
7003     parent = CreateDialogParamA(0, "AUTORADIO_TEST_DIALOG_2", 0, radio_test_dlg_proc, 0);
7004     ok(parent != 0, "failed to create parent window\n");
7005 
7006     radio1 = GetDlgItem(parent, ID_RADIO1);
7007     radio2 = GetDlgItem(parent, ID_RADIO2);
7008     radio3 = GetDlgItem(parent, ID_RADIO3);
7009 
7010     flush_events();
7011     flush_sequence();
7012 
7013     test_radio(radio1, 0, radio2, 0, radio3, 0);
7014     set_radio(radio1, 1, radio2, 1, radio3, 1);
7015     test_radio(radio1, 1, radio2, 1, radio3, 1);
7016 
7017     SetFocus(radio3);
7018 
7019     flush_events();
7020     flush_sequence();
7021 
7022     log_all_parent_messages++;
7023 
7024     SendMessageA(radio3, WM_KEYDOWN, VK_UP, 0);
7025     SendMessageA(radio3, WM_KEYUP, VK_UP, 0);
7026     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7027     ok_sequence(auto_radio_button_VK_UP_child, "press/release VK_UP on auto-radio button", FALSE);
7028 
7029     test_radio(radio1, 1, radio2, 1, radio3, 1);
7030 
7031     flush_events();
7032     flush_sequence();
7033 
7034     DefDlgProcA(parent, WM_KEYDOWN, VK_UP, 0);
7035     DefDlgProcA(parent, WM_KEYUP, VK_UP, 0);
7036     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7037     ok_sequence(auto_radio_button_VK_UP_parent, "press/release VK_UP on dialog", FALSE);
7038 
7039     test_radio(radio1, 1, radio2, 1, radio3, 1);
7040 
7041     SetFocus(radio3);
7042     GetWindowRect(radio3, &rc);
7043 
7044     flush_events();
7045     flush_sequence();
7046 
7047     msg.hwnd = parent;
7048     msg.message = WM_KEYDOWN;
7049     msg.wParam = VK_UP;
7050     msg.lParam = 0;
7051     msg.pt.x = rc.left + 1;
7052     msg.pt.y = rc.top + 1;
7053     ret = IsDialogMessageA(parent, &msg);
7054     ok(ret, "IsDialogMessage should return TRUE\n");
7055     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7056 if (0) /* actual message sequence is different on every run in some Windows setups */
7057     ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #1", FALSE);
7058     /* what really matters is that nothing has changed */
7059     test_radio(radio1, 1, radio2, 1, radio3, 1);
7060 
7061     set_radio(radio1, 0, radio2, 1, radio3, 1);
7062     test_radio(radio1, 0, radio2, 1, radio3, 1);
7063 
7064     flush_events();
7065     flush_sequence();
7066 
7067     ret = IsDialogMessageA(parent, &msg);
7068     ok(ret, "IsDialogMessage should return TRUE\n");
7069     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7070 if (0) /* actual message sequence is different on every run in some Windows setups */
7071     ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #2", FALSE);
7072     /* what really matters is that nothing has changed */
7073     test_radio(radio1, 0, radio2, 1, radio3, 1);
7074 
7075     /* switch from radio3 ro radio1 */
7076     SetFocus(radio3);
7077     GetWindowRect(radio3, &rc);
7078 
7079     flush_events();
7080     flush_sequence();
7081 
7082     msg.hwnd = parent;
7083     msg.message = WM_KEYDOWN;
7084     msg.wParam = VK_DOWN;
7085     msg.lParam = 0;
7086     msg.pt.x = rc.left + 1;
7087     msg.pt.y = rc.top + 1;
7088     ret = IsDialogMessageA(parent, &msg);
7089     ok(ret, "IsDialogMessage should return TRUE\n");
7090     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7091     ok_sequence(auto_radio_button_VK_DOWN_dialog, "IsDialogMessage(VK_DOWN)", TRUE);
7092 
7093     test_radio(radio1, 1, radio2, 0, radio3, 0);
7094 
7095     hwnd = GetFocus();
7096     ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
7097     GetWindowRect(radio1, &rc);
7098 
7099     msg.hwnd = parent;
7100     msg.message = WM_KEYDOWN;
7101     msg.wParam = VK_DOWN;
7102     msg.lParam = 0;
7103     msg.pt.x = rc.left + 1;
7104     msg.pt.y = rc.top + 1;
7105     ret = IsDialogMessageA(parent, &msg);
7106     ok(ret, "IsDialogMessage should return TRUE\n");
7107     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7108     ok_sequence(auto_radio_button_VK_DOWN_radio3, "down to radio3", TRUE);
7109 
7110     test_radio(radio1, 1, radio2, 0, radio3, 0);
7111 
7112     hwnd = GetFocus();
7113     ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
7114 
7115     flush_events();
7116     flush_sequence();
7117 
7118     msg.hwnd = parent;
7119     msg.message = WM_KEYDOWN;
7120     msg.wParam = VK_UP;
7121     msg.lParam = 0;
7122     msg.pt.x = rc.left + 1;
7123     msg.pt.y = rc.top + 1;
7124     ret = IsDialogMessageA(parent, &msg);
7125     ok(ret, "IsDialogMessage should return TRUE\n");
7126     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7127     ok_sequence(auto_radio_button_VK_UP_radio1, "up to radio1", TRUE);
7128 
7129     test_radio(radio1, 1, radio2, 0, radio3, 0);
7130 
7131     hwnd = GetFocus();
7132     ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
7133 
7134     flush_events();
7135     flush_sequence();
7136 
7137     msg.hwnd = parent;
7138     msg.message = WM_KEYDOWN;
7139     msg.wParam = VK_UP;
7140     msg.lParam = 0;
7141     msg.pt.x = rc.left + 1;
7142     msg.pt.y = rc.top + 1;
7143     ret = IsDialogMessageA(parent, &msg);
7144     ok(ret, "IsDialogMessage should return TRUE\n");
7145     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7146 if (0) /* actual message sequence is different on every run in some Windows setups */
7147     ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #3", FALSE);
7148     /* what really matters is that nothing has changed */
7149     test_radio(radio1, 1, radio2, 0, radio3, 0);
7150 
7151     log_all_parent_messages--;
7152 
7153     DestroyWindow(parent);
7154 }
7155 
7156 /****************** static message test *************************/
7157 static const struct message WmSetFontStaticSeq2[] =
7158 {
7159     { WM_SETFONT, sent },
7160     { WM_PAINT, sent|defwinproc|optional },
7161     { WM_ERASEBKGND, sent|defwinproc|optional },
7162     { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
7163     { 0 }
7164 };
7165 
7166 static WNDPROC old_static_proc;
7167 
7168 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7169 {
7170     static LONG defwndproc_counter = 0;
7171     LRESULT ret;
7172     struct recvd_message msg;
7173 
7174     if (ignore_message( message )) return 0;
7175 
7176     msg.hwnd = hwnd;
7177     msg.message = message;
7178     msg.flags = sent|wparam|lparam;
7179     if (defwndproc_counter) msg.flags |= defwinproc;
7180     msg.wParam = wParam;
7181     msg.lParam = lParam;
7182     msg.descr = "static";
7183     add_message(&msg);
7184 
7185     defwndproc_counter++;
7186     ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
7187     defwndproc_counter--;
7188 
7189     return ret;
7190 }
7191 
7192 static void subclass_static(void)
7193 {
7194     WNDCLASSA cls;
7195 
7196     if (!GetClassInfoA(0, "static", &cls)) assert(0);
7197 
7198     old_static_proc = cls.lpfnWndProc;
7199 
7200     cls.hInstance = GetModuleHandleA(NULL);
7201     cls.lpfnWndProc = static_hook_proc;
7202     cls.lpszClassName = "my_static_class";
7203     UnregisterClassA(cls.lpszClassName, cls.hInstance);
7204     if (!RegisterClassA(&cls)) assert(0);
7205 }
7206 
7207 static void test_static_messages(void)
7208 {
7209     /* FIXME: make as comprehensive as the button message test */
7210     static const struct
7211     {
7212 	DWORD style;
7213 	DWORD dlg_code;
7214 	const struct message *setfont;
7215     } static_ctrl[] = {
7216 	{ SS_LEFT, DLGC_STATIC,
7217 	  WmSetFontStaticSeq2 }
7218     };
7219     unsigned int i;
7220     HWND hwnd;
7221     DWORD dlg_code;
7222 
7223     subclass_static();
7224 
7225     for (i = 0; i < ARRAY_SIZE(static_ctrl); i++)
7226     {
7227 	hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
7228 			       0, 0, 50, 14, 0, 0, 0, NULL);
7229 	ok(hwnd != 0, "Failed to create static window\n");
7230 
7231 	dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
7232 	ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
7233 
7234 	ShowWindow(hwnd, SW_SHOW);
7235 	UpdateWindow(hwnd);
7236 	SetFocus(0);
7237 	flush_sequence();
7238 
7239 	trace("static style %08x\n", static_ctrl[i].style);
7240 	SendMessageA(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
7241 	ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
7242 
7243 	DestroyWindow(hwnd);
7244     }
7245 }
7246 
7247 /****************** ComboBox message test *************************/
7248 #define ID_COMBOBOX 0x000f
7249 
7250 static const struct message SetCurSelComboSeq[] =
7251 {
7252     { CB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7253     { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7254     { LB_SETTOPINDEX, sent|wparam|lparam, 0, 0 },
7255     { LB_GETCURSEL, sent|wparam|lparam, 0, 0 },
7256     { LB_GETTEXTLEN, sent|wparam|lparam, 0, 0 },
7257     { LB_GETTEXTLEN, sent|wparam|lparam|optional, 0, 0 }, /* TODO: it's sent on all Windows versions */
7258     { LB_GETTEXT, sent|wparam, 0 },
7259     { WM_CTLCOLOREDIT, sent|parent },
7260     { LB_GETITEMDATA, sent|wparam|lparam, 0, 0 },
7261     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_COMBOBOX, 0x100010f3 },
7262     { 0 }
7263 };
7264 
7265 static const struct message SetCurSelComboSeq2[] =
7266 {
7267     { CB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7268     { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7269     { LB_SETTOPINDEX, sent|wparam|lparam, 0, 0 },
7270     { LB_GETCURSEL, sent|wparam|lparam, 0, 0 },
7271     { LB_GETTEXTLEN, sent|wparam|lparam, 0, 0 },
7272     { LB_GETTEXTLEN, sent|wparam|lparam|optional, 0, 0 }, /* TODO: it's sent on all Windows versions */
7273     { LB_GETTEXT, sent|wparam, 0 },
7274     { 0 }
7275 };
7276 
7277 static const struct message SetCurSelComboSeq_edit[] =
7278 {
7279     { CB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7280     { WM_SETTEXT, sent|wparam, 0 },
7281     { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
7282     { 0 }
7283 };
7284 
7285 static const struct message WmKeyDownComboSeq[] =
7286 {
7287     { WM_KEYDOWN, sent|wparam|lparam, VK_DOWN, 0 },
7288     { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(1000, LBN_SELCHANGE) },
7289     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDOK) },
7290     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELCHANGE) },
7291     { WM_CTLCOLOREDIT, sent|parent },
7292     { WM_KEYUP, sent|wparam|lparam, VK_DOWN, 0 },
7293     { 0 }
7294 };
7295 
7296 static const struct message WmSetPosComboSeq[] =
7297 {
7298     { WM_WINDOWPOSCHANGING, sent },
7299     { WM_NCCALCSIZE, sent|wparam, TRUE },
7300     { WM_CHILDACTIVATE, sent },
7301     { WM_WINDOWPOSCHANGED, sent },
7302     { WM_MOVE, sent|defwinproc },
7303     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
7304     { WM_WINDOWPOSCHANGING, sent|defwinproc },
7305     { WM_NCCALCSIZE, sent|defwinproc|wparam, TRUE },
7306     { WM_WINDOWPOSCHANGED, sent|defwinproc },
7307     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
7308     { 0 }
7309 };
7310 
7311 static const struct message WMSetFocusComboBoxSeq[] =
7312 {
7313     { WM_SETFOCUS, sent },
7314     { WM_KILLFOCUS, sent|parent },
7315     { WM_SETFOCUS, sent },
7316     { WM_COMMAND, sent|defwinproc|wparam, MAKEWPARAM(1001, EN_SETFOCUS) },
7317     { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, INT_MAX },
7318     { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7319     { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7320     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SETFOCUS) },
7321     { 0 }
7322 };
7323 
7324 static const struct message SetFocusButtonSeq[] =
7325 {
7326     { WM_KILLFOCUS, sent },
7327     { CB_GETCOMBOBOXINFO, sent|optional },/* Windows 2000 */
7328     { 0x0167, sent|optional },/* Undocumented message. Sent on all versions except Windows 2000 */
7329     { WM_LBUTTONUP, sent|defwinproc },
7330     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDCANCEL) },
7331     { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, 0 },
7332     { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7333     { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7334     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_KILLFOCUS) },
7335     { WM_CTLCOLORBTN, sent|parent },
7336     { 0 }
7337 };
7338 
7339 static const struct message SetFocusComboBoxSeq[] =
7340 {
7341     { WM_CTLCOLORBTN, sent|parent },
7342     { WM_SETFOCUS, sent },
7343     { WM_KILLFOCUS, sent|defwinproc },
7344     { WM_SETFOCUS, sent },
7345     { WM_COMMAND, sent|defwinproc|wparam, MAKEWPARAM(1001, EN_SETFOCUS) },
7346     { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, INT_MAX },
7347     { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7348     { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7349     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SETFOCUS) },
7350     { 0 }
7351 };
7352 
7353 static const struct message SetFocusButtonSeq2[] =
7354 {
7355     { WM_KILLFOCUS, sent },
7356     { CB_GETCOMBOBOXINFO, sent|optional },/* Windows 2000 */
7357     { 0x0167, sent|optional },/* Undocumented message. Sent on all versions except Windows 2000 */
7358     { WM_LBUTTONUP, sent|defwinproc },
7359     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDCANCEL) },
7360     { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, 0 },
7361     { WM_CTLCOLOREDIT, sent|defwinproc },
7362     { WM_CTLCOLOREDIT, sent|parent },
7363     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_KILLFOCUS) },
7364     { WM_CTLCOLORBTN, sent|parent },
7365     { 0 }
7366 };
7367 
7368 static WNDPROC old_combobox_proc, edit_window_proc, lbox_window_proc;
7369 
7370 static LRESULT CALLBACK combobox_edit_subclass_proc(HWND hwnd, UINT message,
7371         WPARAM wParam, LPARAM lParam)
7372 {
7373     static LONG defwndproc_counter = 0;
7374     LRESULT ret;
7375     struct recvd_message msg;
7376 
7377     /* do not log painting messages */
7378     if (message != WM_PAINT &&
7379         message != WM_NCPAINT &&
7380         message != WM_SYNCPAINT &&
7381         message != WM_ERASEBKGND &&
7382         message != WM_NCHITTEST &&
7383         message != WM_GETTEXT &&
7384         !ignore_message( message ))
7385     {
7386         msg.hwnd = hwnd;
7387         msg.message = message;
7388         msg.flags = sent|wparam|lparam;
7389         if (defwndproc_counter) msg.flags |= defwinproc;
7390         msg.wParam = wParam;
7391         msg.lParam = lParam;
7392         msg.descr = "combo edit";
7393         add_message(&msg);
7394     }
7395 
7396     defwndproc_counter++;
7397     ret = CallWindowProcA(edit_window_proc, hwnd, message, wParam, lParam);
7398     defwndproc_counter--;
7399 
7400     return ret;
7401 }
7402 
7403 static LRESULT CALLBACK combobox_lbox_subclass_proc(HWND hwnd, UINT message,
7404         WPARAM wParam, LPARAM lParam)
7405 {
7406     static LONG defwndproc_counter = 0;
7407     LRESULT ret;
7408     struct recvd_message msg;
7409 
7410     /* do not log painting messages */
7411     if (message != WM_PAINT &&
7412         message != WM_NCPAINT &&
7413         message != WM_SYNCPAINT &&
7414         message != WM_ERASEBKGND &&
7415         message != WM_NCHITTEST &&
7416         !ignore_message( message ))
7417     {
7418         msg.hwnd = hwnd;
7419         msg.message = message;
7420         msg.flags = sent|wparam|lparam;
7421         if (defwndproc_counter) msg.flags |= defwinproc;
7422         msg.wParam = wParam;
7423         msg.lParam = lParam;
7424         msg.descr = "combo lbox";
7425         add_message(&msg);
7426     }
7427 
7428     defwndproc_counter++;
7429     ret = CallWindowProcA(lbox_window_proc, hwnd, message, wParam, lParam);
7430     defwndproc_counter--;
7431 
7432     return ret;
7433 }
7434 
7435 static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7436 {
7437     static LONG defwndproc_counter = 0;
7438     LRESULT ret;
7439     struct recvd_message msg;
7440 
7441     /* do not log painting messages */
7442     if (message != WM_PAINT &&
7443         message != WM_NCPAINT &&
7444         message != WM_SYNCPAINT &&
7445         message != WM_ERASEBKGND &&
7446         message != WM_NCHITTEST &&
7447         message != WM_GETTEXT &&
7448         !ignore_message( message ))
7449     {
7450         msg.hwnd = hwnd;
7451         msg.message = message;
7452         msg.flags = sent|wparam|lparam;
7453         if (defwndproc_counter) msg.flags |= defwinproc;
7454         msg.wParam = wParam;
7455         msg.lParam = lParam;
7456         msg.descr = "combo";
7457         add_message(&msg);
7458     }
7459 
7460     defwndproc_counter++;
7461     ret = CallWindowProcA(old_combobox_proc, hwnd, message, wParam, lParam);
7462     defwndproc_counter--;
7463 
7464     return ret;
7465 }
7466 
7467 static void subclass_combobox(void)
7468 {
7469     WNDCLASSA cls;
7470 
7471     if (!GetClassInfoA(0, "ComboBox", &cls)) assert(0);
7472 
7473     old_combobox_proc = cls.lpfnWndProc;
7474 
7475     cls.hInstance = GetModuleHandleA(NULL);
7476     cls.lpfnWndProc = combobox_hook_proc;
7477     cls.lpszClassName = "my_combobox_class";
7478     UnregisterClassA(cls.lpszClassName, cls.hInstance);
7479     if (!RegisterClassA(&cls)) assert(0);
7480 }
7481 
7482 static void test_combobox_messages(void)
7483 {
7484     HWND parent, combo, button, edit, lbox;
7485     LRESULT ret;
7486     COMBOBOXINFO cbInfo;
7487     BOOL res;
7488 
7489     subclass_combobox();
7490 
7491     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7492                              100, 100, 200, 200, 0, 0, 0, NULL);
7493     ok(parent != 0, "Failed to create parent window\n");
7494     flush_sequence();
7495 
7496     combo = CreateWindowExA(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
7497                            0, 0, 100, 150, parent, (HMENU)ID_COMBOBOX, 0, NULL);
7498     ok(combo != 0, "Failed to create combobox window\n");
7499 
7500     UpdateWindow(combo);
7501 
7502     ret = SendMessageA(combo, WM_GETDLGCODE, 0, 0);
7503     ok(ret == (DLGC_WANTCHARS | DLGC_WANTARROWS), "wrong dlg_code %08lx\n", ret);
7504 
7505     ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
7506     ok(ret == 0, "expected 0, got %ld\n", ret);
7507     ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 1");
7508     ok(ret == 1, "expected 1, got %ld\n", ret);
7509     ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 2");
7510     ok(ret == 2, "expected 2, got %ld\n", ret);
7511 
7512     SendMessageA(combo, CB_SETCURSEL, 0, 0);
7513     SetFocus(combo);
7514     flush_sequence();
7515 
7516     log_all_parent_messages++;
7517     SendMessageA(combo, WM_KEYDOWN, VK_DOWN, 0);
7518     SendMessageA(combo, WM_KEYUP, VK_DOWN, 0);
7519     log_all_parent_messages--;
7520     ok_sequence(WmKeyDownComboSeq, "WM_KEYDOWN/VK_DOWN on a ComboBox", FALSE);
7521 
7522     flush_sequence();
7523     SetWindowPos(combo, 0, 10, 10, 120, 130, SWP_NOZORDER);
7524     ok_sequence(WmSetPosComboSeq, "repositioning messages on a ComboBox", FALSE);
7525 
7526     DestroyWindow(combo);
7527     DestroyWindow(parent);
7528 
7529     /* Start again. Test combobox text selection when getting and losing focus */
7530     parent = CreateWindowExA(0, "TestParentClass", "Parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7531                              10, 10, 300, 300, NULL, NULL, NULL, NULL);
7532     ok(parent != 0, "Failed to create parent window\n");
7533 
7534     combo = CreateWindowExA(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWN,
7535                             5, 5, 100, 100, parent, (HMENU)ID_COMBOBOX, NULL, NULL);
7536     ok(combo != 0, "Failed to create combobox window\n");
7537 
7538     cbInfo.cbSize = sizeof(COMBOBOXINFO);
7539     SetLastError(0xdeadbeef);
7540     res = GetComboBoxInfo(combo, &cbInfo);
7541     ok(res, "Failed to get COMBOBOXINFO structure; LastError: %u\n", GetLastError());
7542     edit = cbInfo.hwndItem;
7543 
7544     edit_window_proc = (WNDPROC)SetWindowLongPtrA(edit, GWLP_WNDPROC,
7545             (ULONG_PTR)combobox_edit_subclass_proc);
7546 
7547     button = CreateWindowExA(0, "Button", "OK", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
7548                              5, 50, 100, 20, parent, NULL,
7549                              (HINSTANCE)GetWindowLongPtrA(parent, GWLP_HINSTANCE), NULL);
7550     ok(button != 0, "Failed to create button window\n");
7551 
7552     flush_sequence();
7553     log_all_parent_messages++;
7554     SendMessageA(combo, WM_SETFOCUS, 0, (LPARAM)edit);
7555     log_all_parent_messages--;
7556     ok_sequence(WMSetFocusComboBoxSeq, "WM_SETFOCUS on a ComboBox", TRUE);
7557 
7558     flush_sequence();
7559     log_all_parent_messages++;
7560     SetFocus(button);
7561     log_all_parent_messages--;
7562     ok_sequence(SetFocusButtonSeq, "SetFocus on a Button", TRUE);
7563 
7564     SendMessageA(combo, WM_SETTEXT, 0, (LPARAM)"Wine Test");
7565 
7566     flush_sequence();
7567     log_all_parent_messages++;
7568     SetFocus(combo);
7569     log_all_parent_messages--;
7570     ok_sequence(SetFocusComboBoxSeq, "SetFocus on a ComboBox", TRUE);
7571 
7572     flush_sequence();
7573     log_all_parent_messages++;
7574     SetFocus(button);
7575     log_all_parent_messages--;
7576     ok_sequence(SetFocusButtonSeq2, "SetFocus on a Button (2)", TRUE);
7577 
7578     SetFocus(combo);
7579     SendMessageA(combo, WM_SETREDRAW, FALSE, 0);
7580     flush_sequence();
7581     log_all_parent_messages++;
7582     SendMessageA(combo, CB_SETCURSEL, 0, 0);
7583     log_all_parent_messages--;
7584     ok_sequence(SetCurSelComboSeq_edit, "CB_SETCURSEL on a ComboBox with edit control", FALSE);
7585 
7586     DestroyWindow(button);
7587     DestroyWindow(combo);
7588 
7589     combo = CreateWindowExA(0, "my_combobox_class", "test",
7590                             WS_CHILD | WS_VISIBLE | CBS_OWNERDRAWFIXED | CBS_DROPDOWNLIST,
7591                             5, 5, 100, 100, parent, (HMENU)ID_COMBOBOX, NULL, NULL);
7592     ok(combo != 0, "Failed to create combobox window\n");
7593 
7594     ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
7595     ok(ret == 0, "expected 0, got %ld\n", ret);
7596 
7597     cbInfo.cbSize = sizeof(COMBOBOXINFO);
7598     SetLastError(0xdeadbeef);
7599     res = GetComboBoxInfo(combo, &cbInfo);
7600     ok(res, "Failed to get COMBOBOXINFO structure; LastError: %u\n", GetLastError());
7601     lbox = cbInfo.hwndList;
7602     lbox_window_proc = (WNDPROC)SetWindowLongPtrA(lbox, GWLP_WNDPROC,
7603             (ULONG_PTR)combobox_lbox_subclass_proc);
7604     flush_sequence();
7605 
7606     log_all_parent_messages++;
7607     SendMessageA(combo, CB_SETCURSEL, 0, 0);
7608     log_all_parent_messages--;
7609     ok_sequence(SetCurSelComboSeq, "CB_SETCURSEL on a ComboBox", FALSE);
7610 
7611     ShowWindow(combo, SW_HIDE);
7612     flush_sequence();
7613     log_all_parent_messages++;
7614     SendMessageA(combo, CB_SETCURSEL, 0, 0);
7615     log_all_parent_messages--;
7616     ok_sequence(SetCurSelComboSeq2, "CB_SETCURSEL on a ComboBox", FALSE);
7617 
7618     DestroyWindow(combo);
7619     DestroyWindow(parent);
7620 }
7621 
7622 /****************** WM_IME_KEYDOWN message test *******************/
7623 
7624 static const struct message WmImeKeydownMsgSeq_0[] =
7625 {
7626     { WM_IME_KEYDOWN, wparam, VK_RETURN },
7627     { WM_CHAR, wparam, 'A' },
7628     { 0 }
7629 };
7630 
7631 static const struct message WmImeKeydownMsgSeq_1[] =
7632 {
7633     { WM_KEYDOWN, optional|wparam, VK_RETURN },
7634     { WM_CHAR,    optional|wparam, VK_RETURN },
7635     { 0 }
7636 };
7637 
7638 static LRESULT WINAPI wmime_keydown_procA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7639 {
7640     struct recvd_message msg;
7641 
7642     msg.hwnd = hwnd;
7643     msg.message = message;
7644     msg.flags = wparam|lparam;
7645     msg.wParam = wParam;
7646     msg.lParam = lParam;
7647     msg.descr = "wmime_keydown";
7648     add_message(&msg);
7649 
7650     return DefWindowProcA(hwnd, message, wParam, lParam);
7651 }
7652 
7653 static void register_wmime_keydown_class(void)
7654 {
7655     WNDCLASSA cls;
7656 
7657     ZeroMemory(&cls, sizeof(WNDCLASSA));
7658     cls.lpfnWndProc = wmime_keydown_procA;
7659     cls.hInstance = GetModuleHandleA(0);
7660     cls.lpszClassName = "wmime_keydown_class";
7661     if (!RegisterClassA(&cls)) assert(0);
7662 }
7663 
7664 static void test_wmime_keydown_message(void)
7665 {
7666     HWND hwnd;
7667     MSG msg;
7668 
7669     trace("Message sequences by WM_IME_KEYDOWN\n");
7670 
7671     register_wmime_keydown_class();
7672     hwnd = CreateWindowExA(0, "wmime_keydown_class", NULL, WS_OVERLAPPEDWINDOW,
7673                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
7674                            NULL, NULL, 0);
7675     flush_events();
7676     flush_sequence();
7677 
7678     SendMessageA(hwnd, WM_IME_KEYDOWN, VK_RETURN, 0x1c0001);
7679     SendMessageA(hwnd, WM_CHAR, 'A', 1);
7680     ok_sequence(WmImeKeydownMsgSeq_0, "WM_IME_KEYDOWN 0", FALSE);
7681 
7682     while ( PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) )
7683     {
7684         TranslateMessage(&msg);
7685         DispatchMessageA(&msg);
7686     }
7687     ok_sequence(WmImeKeydownMsgSeq_1, "WM_IME_KEYDOWN 1", FALSE);
7688 
7689     DestroyWindow(hwnd);
7690 }
7691 
7692 /************* painting message test ********************/
7693 
7694 void dump_region(HRGN hrgn)
7695 {
7696     DWORD i, size;
7697     RGNDATA *data = NULL;
7698     RECT *rect;
7699 
7700     if (!hrgn)
7701     {
7702         printf( "null region\n" );
7703         return;
7704     }
7705     if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
7706     if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
7707     GetRegionData( hrgn, size, data );
7708     printf("%d rects:", data->rdh.nCount );
7709     for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
7710         printf( " %s", wine_dbgstr_rect( rect ));
7711     printf("\n");
7712     HeapFree( GetProcessHeap(), 0, data );
7713 }
7714 
7715 #define check_update_rgn( hwnd, hrgn ) check_update_rgn_( __LINE__, hwnd, hrgn )
7716 static void check_update_rgn_( int line, HWND hwnd, HRGN hrgn )
7717 {
7718     INT ret;
7719     RECT r1, r2;
7720     HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
7721     HRGN update = CreateRectRgn( 0, 0, 0, 0 );
7722 
7723     ret = GetUpdateRgn( hwnd, update, FALSE );
7724     ok( ret != ERROR, "GetUpdateRgn failed\n" );
7725     if (ret == NULLREGION)
7726     {
7727         ok_(__FILE__,line)( !hrgn, "Update region shouldn't be empty\n" );
7728     }
7729     else
7730     {
7731         if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
7732         {
7733             ok_(__FILE__,line)( 0, "Regions are different\n" );
7734             if (winetest_debug > 0)
7735             {
7736                 printf( "Update region: " );
7737                 dump_region( update );
7738                 printf( "Wanted region: " );
7739                 dump_region( hrgn );
7740             }
7741         }
7742     }
7743     GetRgnBox( update, &r1 );
7744     GetUpdateRect( hwnd, &r2, FALSE );
7745     ok_(__FILE__,line)( EqualRect( &r1, &r2 ), "Rectangles are different: %s / %s\n",
7746                         wine_dbgstr_rect( &r1 ), wine_dbgstr_rect( &r2 ));
7747 
7748     DeleteObject( tmp );
7749     DeleteObject( update );
7750 }
7751 
7752 static const struct message WmInvalidateRgn[] = {
7753     { WM_NCPAINT, sent },
7754     { WM_GETTEXT, sent|defwinproc|optional },
7755     { 0 }
7756 };
7757 
7758 static const struct message WmGetUpdateRect[] = {
7759     { WM_NCPAINT, sent },
7760     { WM_GETTEXT, sent|defwinproc|optional },
7761     { WM_PAINT, sent },
7762     { 0 }
7763 };
7764 
7765 static const struct message WmInvalidateFull[] = {
7766     { WM_NCPAINT, sent|wparam, 1 },
7767     { WM_GETTEXT, sent|defwinproc|optional },
7768     { 0 }
7769 };
7770 
7771 static const struct message WmInvalidateErase[] = {
7772     { WM_NCPAINT, sent|wparam, 1 },
7773     { WM_GETTEXT, sent|defwinproc|optional },
7774     { WM_ERASEBKGND, sent },
7775     { 0 }
7776 };
7777 
7778 static const struct message WmInvalidatePaint[] = {
7779     { WM_PAINT, sent },
7780     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
7781     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7782     { 0 }
7783 };
7784 
7785 static const struct message WmInvalidateErasePaint[] = {
7786     { WM_PAINT, sent },
7787     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
7788     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7789     { WM_ERASEBKGND, sent|beginpaint|optional },
7790     { 0 }
7791 };
7792 
7793 static const struct message WmInvalidateErasePaint2[] = {
7794     { WM_PAINT, sent },
7795     { WM_NCPAINT, sent|beginpaint },
7796     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7797     { WM_ERASEBKGND, sent|beginpaint|optional },
7798     { 0 }
7799 };
7800 
7801 static const struct message WmErase[] = {
7802     { WM_ERASEBKGND, sent },
7803     { 0 }
7804 };
7805 
7806 static const struct message WmPaint[] = {
7807     { WM_PAINT, sent },
7808     { 0 }
7809 };
7810 
7811 static const struct message WmParentOnlyPaint[] = {
7812     { WM_PAINT, sent|parent },
7813     { 0 }
7814 };
7815 
7816 static const struct message WmInvalidateParent[] = {
7817     { WM_NCPAINT, sent|parent },
7818     { WM_GETTEXT, sent|defwinproc|parent|optional },
7819     { WM_ERASEBKGND, sent|parent },
7820     { 0 }
7821 };
7822 
7823 static const struct message WmInvalidateParentChild[] = {
7824     { WM_NCPAINT, sent|parent },
7825     { WM_GETTEXT, sent|defwinproc|parent|optional },
7826     { WM_ERASEBKGND, sent|parent },
7827     { WM_NCPAINT, sent },
7828     { WM_GETTEXT, sent|defwinproc|optional },
7829     { WM_ERASEBKGND, sent },
7830     { 0 }
7831 };
7832 
7833 static const struct message WmInvalidateParentChild2[] = {
7834     { WM_ERASEBKGND, sent|parent },
7835     { WM_NCPAINT, sent },
7836     { WM_GETTEXT, sent|defwinproc|optional },
7837     { WM_ERASEBKGND, sent },
7838     { 0 }
7839 };
7840 
7841 static const struct message WmParentPaint[] = {
7842     { WM_PAINT, sent|parent },
7843     { WM_PAINT, sent },
7844     { 0 }
7845 };
7846 
7847 static const struct message WmParentPaintNc[] = {
7848     { WM_PAINT, sent|parent },
7849     { WM_PAINT, sent },
7850     { WM_NCPAINT, sent|beginpaint },
7851     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7852     { WM_ERASEBKGND, sent|beginpaint|optional },
7853     { 0 }
7854 };
7855 
7856 static const struct message WmChildPaintNc[] = {
7857     { WM_PAINT, sent },
7858     { WM_NCPAINT, sent|beginpaint },
7859     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7860     { WM_ERASEBKGND, sent|beginpaint|optional },
7861     { 0 }
7862 };
7863 
7864 static const struct message WmParentErasePaint[] = {
7865     { WM_PAINT, sent|parent },
7866     { WM_NCPAINT, sent|parent|beginpaint },
7867     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
7868     { WM_ERASEBKGND, sent|parent|beginpaint|optional },
7869     { WM_PAINT, sent },
7870     { WM_NCPAINT, sent|beginpaint },
7871     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7872     { WM_ERASEBKGND, sent|beginpaint|optional },
7873     { 0 }
7874 };
7875 
7876 static const struct message WmParentOnlyNcPaint[] = {
7877     { WM_PAINT, sent|parent },
7878     { WM_NCPAINT, sent|parent|beginpaint },
7879     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
7880     { 0 }
7881 };
7882 
7883 static const struct message WmSetParentStyle[] = {
7884     { WM_STYLECHANGING, sent|parent },
7885     { WM_STYLECHANGED, sent|parent },
7886     { 0 }
7887 };
7888 
7889 static void test_paint_messages(void)
7890 {
7891     BOOL ret;
7892     RECT rect, rect2;
7893     POINT pt;
7894     MSG msg;
7895     HWND hparent, hchild;
7896     HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
7897     HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
7898     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
7899                                 100, 100, 200, 200, 0, 0, 0, NULL);
7900     ok (hwnd != 0, "Failed to create overlapped window\n");
7901 
7902     ShowWindow( hwnd, SW_SHOW );
7903     UpdateWindow( hwnd );
7904     flush_events();
7905     flush_sequence();
7906 
7907     check_update_rgn( hwnd, 0 );
7908     SetRectRgn( hrgn, 10, 10, 20, 20 );
7909     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
7910     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7911     check_update_rgn( hwnd, hrgn );
7912     SetRectRgn( hrgn2, 20, 20, 30, 30 );
7913     ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
7914     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7915     CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
7916     check_update_rgn( hwnd, hrgn );
7917     /* validate everything */
7918     ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7919     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7920     check_update_rgn( hwnd, 0 );
7921 
7922     /* test empty region */
7923     SetRectRgn( hrgn, 10, 10, 10, 15 );
7924     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
7925     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7926     check_update_rgn( hwnd, 0 );
7927     /* test empty rect */
7928     SetRect( &rect, 10, 10, 10, 15 );
7929     ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
7930     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7931     check_update_rgn( hwnd, 0 );
7932 
7933     /* flush pending messages */
7934     flush_events();
7935     flush_sequence();
7936 
7937     GetClientRect( hwnd, &rect );
7938     SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
7939     /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
7940      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
7941      */
7942     SetRectEmpty( &rect );
7943     ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) failed\n");
7944     check_update_rgn( hwnd, hrgn );
7945     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
7946     flush_events();
7947     ok_sequence( WmPaint, "Paint", FALSE );
7948     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7949     check_update_rgn( hwnd, 0 );
7950 
7951     SetRectEmpty( &rect );
7952     ok(RedrawWindow(0, &rect, 0, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
7953        "RedrawWindow failed\n");
7954     check_update_rgn( hwnd, 0 );
7955 
7956     SetRectEmpty( &rect );
7957     ok(RedrawWindow(0, &rect, 0, RDW_ALLCHILDREN | RDW_VALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
7958        "RedrawWindow failed\n");
7959     check_update_rgn( hwnd, 0 );
7960 
7961     GetWindowRect( hwnd, &rect );
7962     ok(RedrawWindow(0, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
7963        "RedrawWindow failed\n");
7964     check_update_rgn( hwnd, 0 );
7965 
7966     flush_events();
7967     ok(RedrawWindow(0, &rect, 0, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
7968        "RedrawWindow failed\n");
7969     check_update_rgn( hwnd, hrgn );
7970     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
7971     flush_events();
7972     ok_sequence( WmPaint, "Paint", FALSE );
7973     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7974     check_update_rgn( hwnd, 0 );
7975 
7976     ok(RedrawWindow(GetDesktopWindow(), &rect, 0,
7977                     RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
7978        "RedrawWindow failed\n");
7979     ret = GetUpdateRgn( hwnd, hrgn2, FALSE );
7980     ok( ret == NULLREGION || broken(ret == SIMPLEREGION), /* <= win7 */
7981         "region should be null (%d)\n", ret );
7982     if (ret == SIMPLEREGION) ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
7983     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7984     flush_events();
7985 
7986     ok(RedrawWindow(GetDesktopWindow(), NULL, 0,
7987                     RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
7988        "RedrawWindow failed\n");
7989     ret = GetUpdateRgn( hwnd, hrgn2, FALSE );
7990     ok( ret == NULLREGION || broken(ret == SIMPLEREGION), /* <= win7 */
7991         "region should be null (%d)\n", ret );
7992     if (ret == SIMPLEREGION) ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
7993     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7994     flush_events();
7995 
7996     SetRectRgn( hrgn2, rect.left, rect.top, rect.right, rect.bottom );
7997     ok(RedrawWindow(0, NULL, hrgn2, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
7998        "RedrawWindow failed\n");
7999     check_update_rgn( hwnd, hrgn );
8000     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8001     flush_events();
8002     ok_sequence( WmPaint, "Paint", FALSE );
8003     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8004     check_update_rgn( hwnd, 0 );
8005 
8006     ok(RedrawWindow(0, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ERASENOW ),
8007        "RedrawWindow failed\n");
8008     check_update_rgn( hwnd, 0 );
8009 
8010     ok(RedrawWindow(0, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_ERASE | RDW_ERASENOW ),
8011        "RedrawWindow failed\n");
8012     check_update_rgn( hwnd, hrgn );
8013     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8014     flush_events();
8015     ok_sequence( WmPaint, "Paint", FALSE );
8016     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8017     check_update_rgn( hwnd, 0 );
8018 
8019     /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
8020      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
8021      */
8022     SetRectEmpty( &rect );
8023     if (ValidateRect(0, &rect) && /* not supported on Win9x */
8024         GetUpdateRect(hwnd, NULL, FALSE))  /* or >= Win 8 */
8025     {
8026         check_update_rgn( hwnd, hrgn );
8027         ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8028         flush_events();
8029         ok_sequence( WmPaint, "Paint", FALSE );
8030         RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8031         check_update_rgn( hwnd, 0 );
8032     }
8033 
8034     SetLastError(0xdeadbeef);
8035     ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
8036     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef,
8037        "wrong error code %d\n", GetLastError());
8038     check_update_rgn( hwnd, 0 );
8039     flush_events();
8040     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8041 
8042     SetLastError(0xdeadbeef);
8043     ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
8044     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
8045        broken( GetLastError() == 0xdeadbeef ) /* win9x */,
8046        "wrong error code %d\n", GetLastError());
8047     check_update_rgn( hwnd, 0 );
8048     flush_events();
8049     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8050 
8051     SetLastError(0xdeadbeef);
8052     ok(!UpdateWindow(NULL), "UpdateWindow(NULL) should fail\n");
8053     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
8054        broken( GetLastError() == 0xdeadbeef ) /* win9x */,
8055        "wrong error code %d\n", GetLastError());
8056     check_update_rgn( hwnd, 0 );
8057     flush_events();
8058     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8059 
8060     /* now with frame */
8061     SetRectRgn( hrgn, -5, -5, 20, 20 );
8062 
8063     /* flush pending messages */
8064     flush_events();
8065     flush_sequence();
8066     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8067     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
8068 
8069     SetRectRgn( hrgn, 0, 0, 20, 20 );  /* GetUpdateRgn clips to client area */
8070     check_update_rgn( hwnd, hrgn );
8071 
8072     flush_sequence();
8073     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
8074     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
8075 
8076     flush_sequence();
8077     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
8078     ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
8079 
8080     GetClientRect( hwnd, &rect );
8081     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8082     check_update_rgn( hwnd, hrgn );
8083 
8084     flush_sequence();
8085     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
8086     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8087 
8088     flush_sequence();
8089     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
8090     ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
8091     check_update_rgn( hwnd, 0 );
8092 
8093     flush_sequence();
8094     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
8095     ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
8096     check_update_rgn( hwnd, 0 );
8097 
8098     flush_sequence();
8099     SetRectRgn( hrgn, 0, 0, 100, 100 );
8100     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
8101     SetRectRgn( hrgn, 0, 0, 50, 100 );
8102     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
8103     SetRectRgn( hrgn, 50, 0, 100, 100 );
8104     check_update_rgn( hwnd, hrgn );
8105     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
8106     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );  /* must not generate messages, everything is valid */
8107     check_update_rgn( hwnd, 0 );
8108 
8109     flush_sequence();
8110     SetRectRgn( hrgn, 0, 0, 100, 100 );
8111     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
8112     SetRectRgn( hrgn, 0, 0, 100, 50 );
8113     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
8114     ok_sequence( WmErase, "Erase", FALSE );
8115     SetRectRgn( hrgn, 0, 50, 100, 100 );
8116     check_update_rgn( hwnd, hrgn );
8117 
8118     flush_sequence();
8119     SetRectRgn( hrgn, 0, 0, 100, 100 );
8120     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
8121     SetRectRgn( hrgn, 0, 0, 50, 50 );
8122     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
8123     ok_sequence( WmPaint, "Paint", FALSE );
8124 
8125     flush_sequence();
8126     SetRectRgn( hrgn, -4, -4, -2, -2 );
8127     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8128     SetRectRgn( hrgn, -200, -200, -198, -198 );
8129     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
8130     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
8131 
8132     flush_sequence();
8133     SetRectRgn( hrgn, -4, -4, -2, -2 );
8134     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8135     SetRectRgn( hrgn, -4, -4, -3, -3 );
8136     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
8137     SetRectRgn( hrgn, 0, 0, 1, 1 );
8138     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
8139     ok_sequence( WmPaint, "Paint", FALSE );
8140 
8141     flush_sequence();
8142     SetRectRgn( hrgn, -4, -4, -1, -1 );
8143     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8144     RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
8145     /* make sure no WM_PAINT was generated */
8146     flush_events();
8147     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
8148 
8149     flush_sequence();
8150     SetRectRgn( hrgn, -4, -4, -1, -1 );
8151     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8152     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
8153     {
8154         if (msg.hwnd == hwnd && msg.message == WM_PAINT)
8155         {
8156             /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
8157             INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
8158             ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
8159             ret = GetUpdateRect( hwnd, &rect, FALSE );
8160             ok( ret, "Invalid GetUpdateRect result %d\n", ret );
8161             /* this will send WM_NCPAINT and validate the non client area */
8162             ret = GetUpdateRect( hwnd, &rect, TRUE );
8163             ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
8164         }
8165         DispatchMessageA( &msg );
8166     }
8167     ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
8168 
8169     DestroyWindow( hwnd );
8170 
8171     /* now test with a child window */
8172 
8173     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
8174                               100, 100, 200, 200, 0, 0, 0, NULL);
8175     ok (hparent != 0, "Failed to create parent window\n");
8176 
8177     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
8178                            10, 10, 100, 100, hparent, 0, 0, NULL);
8179     ok (hchild != 0, "Failed to create child window\n");
8180 
8181     ShowWindow( hparent, SW_SHOW );
8182     UpdateWindow( hparent );
8183     UpdateWindow( hchild );
8184     flush_events();
8185     flush_sequence();
8186     log_all_parent_messages++;
8187 
8188     SetRect( &rect, 0, 0, 50, 50 );
8189     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8190     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
8191     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
8192 
8193     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8194     pt.x = pt.y = 0;
8195     MapWindowPoints( hchild, hparent, &pt, 1 );
8196     SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
8197     check_update_rgn( hchild, hrgn );
8198     SetRectRgn( hrgn, 0, 0, 50, 50 );
8199     check_update_rgn( hparent, hrgn );
8200     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8201     ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
8202     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
8203     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
8204 
8205     flush_events();
8206     ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
8207 
8208     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
8209     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8210     ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
8211     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
8212     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
8213 
8214     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
8215     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
8216     ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
8217 
8218     SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
8219     flush_sequence();
8220     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
8221     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8222     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
8223 
8224     /* flush all paint messages */
8225     flush_events();
8226     flush_sequence();
8227 
8228     /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
8229     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
8230     SetRectRgn( hrgn, 0, 0, 50, 50 );
8231     check_update_rgn( hparent, hrgn );
8232     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
8233     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8234     SetRectRgn( hrgn, 0, 0, 50, 50 );
8235     check_update_rgn( hparent, hrgn );
8236 
8237     /* flush all paint messages */
8238     flush_events();
8239     SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
8240     flush_sequence();
8241 
8242     /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
8243     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8244     SetRectRgn( hrgn, 0, 0, 50, 50 );
8245     check_update_rgn( hparent, hrgn );
8246     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
8247     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8248     SetRectRgn( hrgn2, 10, 10, 50, 50 );
8249     CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
8250     check_update_rgn( hparent, hrgn );
8251     /* flush all paint messages */
8252     flush_events();
8253     flush_sequence();
8254 
8255     /* same as above but parent gets completely validated */
8256     SetRect( &rect, 20, 20, 30, 30 );
8257     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8258     SetRectRgn( hrgn, 20, 20, 30, 30 );
8259     check_update_rgn( hparent, hrgn );
8260     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
8261     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8262     check_update_rgn( hparent, 0 );  /* no update region */
8263     flush_events();
8264     ok_sequence( WmEmptySeq, "WmEmpty", FALSE );  /* and no paint messages */
8265 
8266     /* make sure RDW_VALIDATE on child doesn't have the same effect */
8267     flush_sequence();
8268     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8269     SetRectRgn( hrgn, 20, 20, 30, 30 );
8270     check_update_rgn( hparent, hrgn );
8271     RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
8272     SetRectRgn( hrgn, 20, 20, 30, 30 );
8273     check_update_rgn( hparent, hrgn );
8274 
8275     /* same as above but normal WM_PAINT doesn't validate parent */
8276     flush_sequence();
8277     SetRect( &rect, 20, 20, 30, 30 );
8278     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8279     SetRectRgn( hrgn, 20, 20, 30, 30 );
8280     check_update_rgn( hparent, hrgn );
8281     /* no WM_PAINT in child while parent still pending */
8282     while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8283     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8284     while (PeekMessageA( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8285     ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
8286 
8287     flush_sequence();
8288     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8289     /* no WM_PAINT in child while parent still pending */
8290     while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8291     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8292     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
8293     /* now that parent is valid child should get WM_PAINT */
8294     while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8295     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8296     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8297     ok_sequence( WmEmptySeq, "No other message", FALSE );
8298 
8299     /* same thing with WS_CLIPCHILDREN in parent */
8300     flush_sequence();
8301     SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
8302     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
8303     /* changing style invalidates non client area, but we need to invalidate something else to see it */
8304     RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
8305     ok_sequence( WmEmptySeq, "No message", FALSE );
8306     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
8307     ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
8308 
8309     flush_sequence();
8310     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
8311     SetRectRgn( hrgn, 20, 20, 30, 30 );
8312     check_update_rgn( hparent, hrgn );
8313     /* no WM_PAINT in child while parent still pending */
8314     while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8315     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8316     /* WM_PAINT in parent first */
8317     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8318     ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
8319 
8320     /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
8321     flush_sequence();
8322     SetRect( &rect, 0, 0, 30, 30 );
8323     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
8324     SetRectRgn( hrgn, 0, 0, 30, 30 );
8325     check_update_rgn( hparent, hrgn );
8326     flush_events();
8327     ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
8328 
8329     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
8330     flush_sequence();
8331     SetRect( &rect, -10, 0, 30, 30 );
8332     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
8333     SetRect( &rect, 0, 0, 20, 20 );
8334     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
8335     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
8336     ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
8337 
8338     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
8339     flush_sequence();
8340     SetRect( &rect, -10, 0, 30, 30 );
8341     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
8342     SetRect( &rect, 0, 0, 100, 100 );
8343     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
8344     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
8345     ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
8346     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8347     ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
8348 
8349     /* WS_CLIPCHILDREN doesn't exclude children from update region */
8350     flush_sequence();
8351     RedrawWindow( hparent, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
8352     GetClientRect( hparent, &rect );
8353     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8354     check_update_rgn( hparent, hrgn );
8355     flush_events();
8356 
8357     RedrawWindow( hparent, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
8358     GetClientRect( hparent, &rect );
8359     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8360     check_update_rgn( hparent, hrgn );
8361     flush_events();
8362 
8363     /* test RDW_INTERNALPAINT behavior */
8364 
8365     flush_sequence();
8366     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
8367     flush_events();
8368     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
8369 
8370     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
8371     flush_events();
8372     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
8373 
8374     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
8375     flush_events();
8376     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
8377 
8378     assert( GetWindowLongA(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
8379     UpdateWindow( hparent );
8380     flush_events();
8381     flush_sequence();
8382     trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
8383     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8384     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
8385                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8386     flush_events();
8387     ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
8388 
8389     UpdateWindow( hparent );
8390     flush_events();
8391     flush_sequence();
8392     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
8393     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8394     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
8395                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8396     flush_events();
8397     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
8398 
8399     SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
8400     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
8401     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
8402     flush_events();
8403     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
8404 
8405     assert( !(GetWindowLongA(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
8406     UpdateWindow( hparent );
8407     flush_events();
8408     flush_sequence();
8409     trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
8410     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8411     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
8412                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8413     flush_events();
8414     ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
8415 
8416     UpdateWindow( hparent );
8417     flush_events();
8418     flush_sequence();
8419     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
8420     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8421     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
8422                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8423     flush_events();
8424     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
8425 
8426     ok(GetWindowLongA( hparent, GWL_STYLE ) & WS_VISIBLE, "parent should be visible\n");
8427     ok(GetWindowLongA( hchild, GWL_STYLE ) & WS_VISIBLE, "child should be visible\n");
8428 
8429     UpdateWindow( hparent );
8430     flush_events();
8431     flush_sequence();
8432     trace("testing SetWindowPos(-10000, -10000) on child\n");
8433     SetWindowPos( hchild, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
8434     check_update_rgn( hchild, 0 );
8435     flush_events();
8436 
8437 #if 0 /* this one doesn't pass under Wine yet */
8438     UpdateWindow( hparent );
8439     flush_events();
8440     flush_sequence();
8441     trace("testing ShowWindow(SW_MINIMIZE) on child\n");
8442     ShowWindow( hchild, SW_MINIMIZE );
8443     check_update_rgn( hchild, 0 );
8444     flush_events();
8445 #endif
8446 
8447     UpdateWindow( hparent );
8448     flush_events();
8449     flush_sequence();
8450     trace("testing SetWindowPos(-10000, -10000) on parent\n");
8451     SetWindowPos( hparent, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
8452     check_update_rgn( hparent, 0 );
8453     flush_events();
8454 
8455     log_all_parent_messages--;
8456     DestroyWindow( hparent );
8457     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
8458 
8459     /* tests for moving windows off-screen (needs simple WS_POPUP windows) */
8460 
8461     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_POPUP | WS_VISIBLE,
8462                               100, 100, 200, 200, 0, 0, 0, NULL);
8463     ok (hparent != 0, "Failed to create parent window\n");
8464 
8465     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
8466                            10, 10, 100, 100, hparent, 0, 0, NULL);
8467     ok (hchild != 0, "Failed to create child window\n");
8468 
8469     ShowWindow( hparent, SW_SHOW );
8470     UpdateWindow( hparent );
8471     UpdateWindow( hchild );
8472     flush_events();
8473     flush_sequence();
8474 
8475     /* moving child outside of parent boundaries changes update region */
8476     SetRect( &rect, 0, 0, 40, 40 );
8477     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
8478     SetRectRgn( hrgn, 0, 0, 40, 40 );
8479     check_update_rgn( hchild, hrgn );
8480     MoveWindow( hchild, -10, 10, 100, 100, FALSE );
8481     SetRectRgn( hrgn, 10, 0, 40, 40 );
8482     check_update_rgn( hchild, hrgn );
8483     MoveWindow( hchild, -10, -10, 100, 100, FALSE );
8484     SetRectRgn( hrgn, 10, 10, 40, 40 );
8485     check_update_rgn( hchild, hrgn );
8486 
8487     /* moving parent off-screen does too */
8488     SetRect( &rect, 0, 0, 100, 100 );
8489     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
8490     SetRectRgn( hrgn, 0, 0, 100, 100 );
8491     check_update_rgn( hparent, hrgn );
8492     SetRectRgn( hrgn, 10, 10, 40, 40 );
8493     check_update_rgn( hchild, hrgn );
8494     MoveWindow( hparent, -20, -20, 200, 200, FALSE );
8495     GetUpdateRect( hparent, &rect2, FALSE );
8496     if (!EqualRect( &rect2, &rect )) /* Win 8 and later don't crop update to screen */
8497     {
8498         rect.left += 20;
8499         rect.top += 20;
8500     }
8501     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8502     check_update_rgn( hparent, hrgn );
8503     SetRectRgn( hrgn, rect.left + 10, rect.top + 10, 40, 40 );
8504     check_update_rgn( hchild, hrgn );
8505 
8506     /* invalidated region is cropped by the parent rects */
8507     SetRect( &rect, 0, 0, 50, 50 );
8508     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
8509     SetRectRgn( hrgn, rect2.left + 10, rect2.top + 10, 50, 50 );
8510     check_update_rgn( hchild, hrgn );
8511 
8512     DestroyWindow( hparent );
8513     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
8514     flush_sequence();
8515 
8516     DeleteObject( hrgn );
8517     DeleteObject( hrgn2 );
8518 }
8519 
8520 struct wnd_event
8521 {
8522     HWND hwnd;
8523     HANDLE grand_child;
8524     HANDLE start_event;
8525     HANDLE stop_event;
8526 };
8527 
8528 static DWORD WINAPI thread_proc(void *param)
8529 {
8530     MSG msg;
8531     struct wnd_event *wnd_event = param;
8532 
8533     wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
8534                                       100, 100, 200, 200, 0, 0, 0, NULL);
8535     ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
8536 
8537     SetEvent(wnd_event->start_event);
8538 
8539     while (GetMessageA(&msg, 0, 0, 0))
8540     {
8541 	TranslateMessage(&msg);
8542 	DispatchMessageA(&msg);
8543     }
8544 
8545     ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
8546 
8547     return 0;
8548 }
8549 
8550 static DWORD CALLBACK create_grand_child_thread( void *param )
8551 {
8552     struct wnd_event *wnd_event = param;
8553     HWND hchild;
8554     MSG msg;
8555 
8556     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
8557                              WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
8558     ok (hchild != 0, "Failed to create child window\n");
8559     flush_events();
8560     flush_sequence();
8561     SetEvent( wnd_event->start_event );
8562 
8563     for (;;)
8564     {
8565         MsgWaitForMultipleObjects(0, NULL, FALSE, 1000, QS_ALLINPUT);
8566         if (!IsWindow( hchild )) break;  /* will be destroyed when parent thread exits */
8567         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8568     }
8569     return 0;
8570 }
8571 
8572 static DWORD CALLBACK create_child_thread( void *param )
8573 {
8574     struct wnd_event *wnd_event = param;
8575     struct wnd_event child_event;
8576     DWORD ret, tid;
8577     MSG msg;
8578 
8579     child_event.hwnd = CreateWindowExA(0, "TestWindowClass", "Test child",
8580                              WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
8581     ok (child_event.hwnd != 0, "Failed to create child window\n");
8582     SetFocus( child_event.hwnd );
8583     flush_events();
8584     flush_sequence();
8585     child_event.start_event = wnd_event->start_event;
8586     wnd_event->grand_child = CreateThread(NULL, 0, create_grand_child_thread, &child_event, 0, &tid);
8587     for (;;)
8588     {
8589         DWORD ret = MsgWaitForMultipleObjects(1, &child_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
8590         if (ret != 1) break;
8591         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8592     }
8593     ret = WaitForSingleObject( wnd_event->stop_event, 5000 );
8594     ok( !ret, "WaitForSingleObject failed %x\n", ret );
8595     return 0;
8596 }
8597 
8598 static const char manifest_dep[] =
8599 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
8600 "<assemblyIdentity version=\"1.2.3.4\"  name=\"testdep1\" type=\"win32\" processorArchitecture=\"" ARCH "\"/>"
8601 "    <file name=\"testdep.dll\" />"
8602 "</assembly>";
8603 
8604 static const char manifest_main[] =
8605 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
8606 "<assemblyIdentity version=\"1.2.3.4\" name=\"Wine.Test\" type=\"win32\" />"
8607 "<dependency>"
8608 " <dependentAssembly>"
8609 "  <assemblyIdentity type=\"win32\" name=\"testdep1\" version=\"1.2.3.4\" processorArchitecture=\"" ARCH "\" />"
8610 " </dependentAssembly>"
8611 "</dependency>"
8612 "</assembly>";
8613 
8614 static void create_manifest_file(const char *filename, const char *manifest)
8615 {
8616     WCHAR path[MAX_PATH];
8617     HANDLE file;
8618     DWORD size;
8619 
8620     MultiByteToWideChar( CP_ACP, 0, filename, -1, path, MAX_PATH );
8621     file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8622     ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
8623     WriteFile(file, manifest, strlen(manifest), &size, NULL);
8624     CloseHandle(file);
8625 }
8626 
8627 static HANDLE test_create(const char *file)
8628 {
8629     WCHAR path[MAX_PATH];
8630     ACTCTXW actctx;
8631     HANDLE handle;
8632 
8633     MultiByteToWideChar(CP_ACP, 0, file, -1, path, MAX_PATH);
8634     memset(&actctx, 0, sizeof(ACTCTXW));
8635     actctx.cbSize = sizeof(ACTCTXW);
8636     actctx.lpSource = path;
8637 
8638     handle = pCreateActCtxW(&actctx);
8639     ok(handle != INVALID_HANDLE_VALUE, "failed to create context, error %u\n", GetLastError());
8640 
8641     ok(actctx.cbSize == sizeof(actctx), "cbSize=%d\n", actctx.cbSize);
8642     ok(actctx.dwFlags == 0, "dwFlags=%d\n", actctx.dwFlags);
8643     ok(actctx.lpSource == path, "lpSource=%p\n", actctx.lpSource);
8644     ok(actctx.wProcessorArchitecture == 0, "wProcessorArchitecture=%d\n", actctx.wProcessorArchitecture);
8645     ok(actctx.wLangId == 0, "wLangId=%d\n", actctx.wLangId);
8646     ok(actctx.lpAssemblyDirectory == NULL, "lpAssemblyDirectory=%p\n", actctx.lpAssemblyDirectory);
8647     ok(actctx.lpResourceName == NULL, "lpResourceName=%p\n", actctx.lpResourceName);
8648     ok(actctx.lpApplicationName == NULL, "lpApplicationName=%p\n", actctx.lpApplicationName);
8649     ok(actctx.hModule == NULL, "hModule=%p\n", actctx.hModule);
8650 
8651     return handle;
8652 }
8653 
8654 static void test_interthread_messages(void)
8655 {
8656     HANDLE hThread, context, handle, event;
8657     ULONG_PTR cookie;
8658     DWORD tid;
8659     WNDPROC proc;
8660     MSG msg;
8661     char buf[256];
8662     int len, expected_len;
8663     struct wnd_event wnd_event;
8664     BOOL ret;
8665 
8666     wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
8667     if (!wnd_event.start_event)
8668     {
8669         win_skip("skipping interthread message test under win9x\n");
8670         return;
8671     }
8672 
8673     hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
8674     ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
8675 
8676     ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8677 
8678     CloseHandle(wnd_event.start_event);
8679 
8680     SetLastError(0xdeadbeef);
8681     ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeeded\n");
8682     ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == 0xdeadbeef,
8683        "wrong error code %d\n", GetLastError());
8684 
8685     proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
8686     ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %d\n", GetLastError());
8687 
8688     expected_len = lstrlenA("window caption text");
8689     memset(buf, 0, sizeof(buf));
8690     SetLastError(0xdeadbeef);
8691     len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
8692     ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %d, len %d, expected len %d\n", GetLastError(), len, expected_len);
8693     ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
8694 
8695     msg.hwnd = wnd_event.hwnd;
8696     msg.message = WM_GETTEXT;
8697     msg.wParam = sizeof(buf);
8698     msg.lParam = (LPARAM)buf;
8699     memset(buf, 0, sizeof(buf));
8700     SetLastError(0xdeadbeef);
8701     len = DispatchMessageA(&msg);
8702     ok((!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY) || broken(len), /* nt4 */
8703        "DispatchMessageA(WM_GETTEXT) succeeded on another thread window: ret %d, error %d\n", len, GetLastError());
8704 
8705     /* the following test causes an exception in user.exe under win9x */
8706     msg.hwnd = wnd_event.hwnd;
8707     msg.message = WM_TIMER;
8708     msg.wParam = 0;
8709     msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
8710     SetLastError(0xdeadbeef);
8711     len = DispatchMessageA(&msg);
8712     ok(!len && GetLastError() == 0xdeadbeef,
8713        "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %d\n", len, GetLastError());
8714 
8715     ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
8716     ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
8717 
8718     ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8719     CloseHandle(hThread);
8720 
8721     ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
8722 
8723     wnd_event.hwnd = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8724                               100, 100, 200, 200, 0, 0, 0, NULL);
8725     ok (wnd_event.hwnd != 0, "Failed to create parent window\n");
8726     flush_events();
8727     flush_sequence();
8728     log_all_parent_messages++;
8729     wnd_event.start_event = CreateEventA( NULL, TRUE, FALSE, NULL );
8730     wnd_event.stop_event = CreateEventA( NULL, TRUE, FALSE, NULL );
8731     hThread = CreateThread( NULL, 0, create_child_thread, &wnd_event, 0, &tid );
8732     for (;;)
8733     {
8734         ret = MsgWaitForMultipleObjects(1, &wnd_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
8735         if (ret != 1) break;
8736         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8737     }
8738     ok( !ret, "MsgWaitForMultipleObjects failed %x\n", ret );
8739     /* now wait for the thread without processing messages; this shouldn't deadlock */
8740     SetEvent( wnd_event.stop_event );
8741     ret = WaitForSingleObject( hThread, 5000 );
8742     ok( !ret, "WaitForSingleObject failed %x\n", ret );
8743     CloseHandle( hThread );
8744 
8745     ret = WaitForSingleObject( wnd_event.grand_child, 5000 );
8746     ok( !ret, "WaitForSingleObject failed %x\n", ret );
8747     CloseHandle( wnd_event.grand_child );
8748 
8749     CloseHandle( wnd_event.start_event );
8750     CloseHandle( wnd_event.stop_event );
8751     flush_events();
8752     ok_sequence(WmExitThreadSeq, "destroy child on thread exit", FALSE);
8753     log_all_parent_messages--;
8754     DestroyWindow( wnd_event.hwnd );
8755 
8756     /* activation context tests */
8757     if (!pActivateActCtx)
8758     {
8759         win_skip("Activation contexts are not supported, skipping\n");
8760         return;
8761     }
8762 
8763     create_manifest_file("testdep1.manifest", manifest_dep);
8764     create_manifest_file("main.manifest", manifest_main);
8765 
8766     context = test_create("main.manifest");
8767     DeleteFileA("testdep1.manifest");
8768     DeleteFileA("main.manifest");
8769 
8770     handle = (void*)0xdeadbeef;
8771     ret = pGetCurrentActCtx(&handle);
8772     ok(ret, "GetCurrentActCtx failed: %u\n", GetLastError());
8773     ok(handle == 0, "active context %p\n", handle);
8774 
8775     wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
8776     hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
8777     ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
8778     ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8779     CloseHandle(wnd_event.start_event);
8780 
8781     /* context is activated after thread creation, so it doesn't inherit it by default */
8782     ret = pActivateActCtx(context, &cookie);
8783     ok(ret, "activation failed: %u\n", GetLastError());
8784 
8785     handle = 0;
8786     ret = pGetCurrentActCtx(&handle);
8787     ok(ret, "GetCurrentActCtx failed: %u\n", GetLastError());
8788     ok(handle != 0, "active context %p\n", handle);
8789     pReleaseActCtx(handle);
8790 
8791     /* destination window will test for active context */
8792     ret = SendMessageA(wnd_event.hwnd, WM_USER+10, 0, 0);
8793     ok(ret, "thread window returned %d\n", ret);
8794 
8795     event = CreateEventW(NULL, 0, 0, NULL);
8796     ret = PostMessageA(wnd_event.hwnd, WM_USER+10, 0, (LPARAM)event);
8797     ok(ret, "thread window returned %d\n", ret);
8798     ok(WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8799     CloseHandle(event);
8800 
8801     ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
8802     ok(ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
8803 
8804     ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8805     CloseHandle(hThread);
8806 
8807     ret = pDeactivateActCtx(0, cookie);
8808     ok(ret, "DeactivateActCtx failed: %u\n", GetLastError());
8809     pReleaseActCtx(context);
8810 }
8811 
8812 
8813 static const struct message WmVkN[] = {
8814     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8815     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8816     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
8817     { WM_CHAR, wparam|lparam, 'n', 1 },
8818     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
8819     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8820     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8821     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8822     { 0 }
8823 };
8824 static const struct message WmShiftVkN[] = {
8825     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
8826     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
8827     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
8828     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8829     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8830     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
8831     { WM_CHAR, wparam|lparam, 'N', 1 },
8832     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
8833     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8834     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8835     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8836     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
8837     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
8838     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
8839     { 0 }
8840 };
8841 static const struct message WmCtrlVkN[] = {
8842     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8843     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8844     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8845     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8846     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8847     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
8848     { WM_CHAR, wparam|lparam, 0x000e, 1 },
8849     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
8850     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8851     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8852     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8853     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8854     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8855     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8856     { 0 }
8857 };
8858 static const struct message WmCtrlVkN_2[] = {
8859     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8860     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8861     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8862     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8863     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8864     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
8865     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8866     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8867     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8868     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8869     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8870     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8871     { 0 }
8872 };
8873 static const struct message WmAltVkN[] = {
8874     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8875     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8876     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8877     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8878     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
8879     { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
8880     { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
8881     { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
8882     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
8883     { HCBT_SYSCOMMAND, hook },
8884     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8885     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8886     { 0x00AE, sent|defwinproc|optional }, /* XP */
8887     { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
8888     { WM_INITMENU, sent|defwinproc },
8889     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8890     { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
8891     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8892     { WM_CAPTURECHANGED, sent|defwinproc },
8893     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
8894     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8895     { WM_EXITMENULOOP, sent|defwinproc },
8896     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
8897     { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
8898     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8899     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
8900     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8901     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8902     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8903     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8904     { 0 }
8905 };
8906 static const struct message WmAltVkN_2[] = {
8907     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8908     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8909     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8910     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8911     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
8912     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
8913     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8914     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
8915     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8916     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8917     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8918     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8919     { 0 }
8920 };
8921 static const struct message WmCtrlAltVkN[] = {
8922     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8923     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8924     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8925     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8926     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8927     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8928     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8929     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
8930     { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
8931     { WM_CHAR, optional },
8932     { WM_CHAR, sent|optional },
8933     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8934     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
8935     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8936     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8937     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8938     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8939     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8940     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8941     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8942     { 0 }
8943 };
8944 static const struct message WmCtrlShiftVkN[] = {
8945     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8946     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8947     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8948     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
8949     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
8950     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
8951     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8952     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8953     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
8954     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8955     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8956     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8957     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
8958     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
8959     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
8960     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8961     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8962     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8963     { 0 }
8964 };
8965 static const struct message WmCtrlAltShiftVkN[] = {
8966     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8967     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8968     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8969     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8970     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8971     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8972     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
8973     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
8974     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
8975     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8976     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
8977     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
8978     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8979     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
8980     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8981     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
8982     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
8983     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
8984     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8985     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8986     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8987     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8988     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8989     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8990     { 0 }
8991 };
8992 static const struct message WmAltPressRelease[] = {
8993     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8994     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8995     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8996     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8997     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8998     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8999     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
9000     { HCBT_SYSCOMMAND, hook },
9001     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
9002     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
9003     { WM_INITMENU, sent|defwinproc },
9004     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
9005     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
9006     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
9007 
9008     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
9009 
9010     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
9011     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
9012     { WM_CAPTURECHANGED, sent|defwinproc },
9013     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
9014     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
9015     { WM_EXITMENULOOP, sent|defwinproc },
9016     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
9017     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
9018     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
9019     { 0 }
9020 };
9021 static const struct message WmShiftMouseButton[] = {
9022     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
9023     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
9024     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
9025     { WM_MOUSEMOVE, wparam|optional, 0, 0 },
9026     { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
9027     { WM_LBUTTONDOWN, wparam, MK_LBUTTON|MK_SHIFT, 0 },
9028     { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON|MK_SHIFT, 0 },
9029     { WM_LBUTTONUP, wparam, MK_SHIFT, 0 },
9030     { WM_LBUTTONUP, sent|wparam, MK_SHIFT, 0 },
9031     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
9032     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
9033     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
9034     { 0 }
9035 };
9036 static const struct message WmF1Seq[] = {
9037     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
9038     { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
9039     { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
9040     { WM_KEYF1, wparam|lparam, 0, 0 },
9041     { WM_KEYF1, sent|wparam|lparam, 0, 0 },
9042     { WM_HELP, sent|defwinproc },
9043     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
9044     { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
9045     { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
9046     { 0 }
9047 };
9048 static const struct message WmVkAppsSeq[] = {
9049     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
9050     { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
9051     { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
9052     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
9053     { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
9054     { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
9055     { WM_CONTEXTMENU, lparam, /*hwnd*/0, -1 },
9056     { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, -1 },
9057     { 0 }
9058 };
9059 static const struct message WmVkF10Seq[] = {
9060     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
9061     { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
9062     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
9063     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
9064     { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
9065     { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
9066     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
9067     { HCBT_SYSCOMMAND, hook },
9068     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
9069     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
9070     { WM_INITMENU, sent|defwinproc },
9071     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
9072     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
9073     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
9074 
9075     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0x10000001 }, /* XP */
9076 
9077     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
9078     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
9079     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
9080     { WM_CAPTURECHANGED, sent|defwinproc },
9081     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
9082     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
9083     { WM_EXITMENULOOP, sent|defwinproc },
9084     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
9085     { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
9086     { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
9087     { 0 }
9088 };
9089 static const struct message WmShiftF10Seq[] = {
9090     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
9091     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
9092     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x00000001 },
9093     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
9094     { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
9095     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
9096     { WM_CONTEXTMENU, sent|defwinproc|lparam, /*hwnd*/0, -1 },
9097     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
9098     { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
9099     { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
9100     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
9101     { HCBT_SYSCOMMAND, hook },
9102     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
9103     { WM_INITMENU, sent|defwinproc },
9104     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
9105     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xd0000001 }, /* XP */
9106     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0x10000001 }, /* XP */
9107     { WM_CAPTURECHANGED, sent|defwinproc|wparam|lparam, 0, 0 },
9108     { WM_MENUSELECT, sent|defwinproc|wparam|lparam, 0xffff0000, 0 },
9109     { WM_EXITMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
9110     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 }, /* XP */
9111     { WM_KEYUP, wparam|lparam, VK_ESCAPE, 0xc0000001 },
9112     { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
9113     { 0 }
9114 };
9115 
9116 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
9117 {
9118     MSG msg;
9119 
9120     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
9121     {
9122         struct recvd_message log_msg;
9123 
9124         /* ignore some unwanted messages */
9125         if (msg.message == WM_MOUSEMOVE ||
9126             msg.message == WM_TIMER ||
9127             ignore_message( msg.message ))
9128             continue;
9129 
9130         log_msg.hwnd = msg.hwnd;
9131         log_msg.message = msg.message;
9132         log_msg.flags = wparam|lparam;
9133         log_msg.wParam = msg.wParam;
9134         log_msg.lParam = msg.lParam;
9135         log_msg.descr = "accel";
9136         add_message(&log_msg);
9137 
9138         if (!hAccel || !TranslateAcceleratorA(hwnd, hAccel, &msg))
9139         {
9140             TranslateMessage(&msg);
9141             DispatchMessageA(&msg);
9142         }
9143     }
9144 }
9145 
9146 static void test_accelerators(void)
9147 {
9148     RECT rc;
9149     POINT pt;
9150     SHORT state;
9151     HACCEL hAccel;
9152     HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9153                                 100, 100, 200, 200, 0, 0, 0, NULL);
9154     BOOL ret;
9155 
9156     assert(hwnd != 0);
9157     UpdateWindow(hwnd);
9158     flush_events();
9159     flush_sequence();
9160 
9161     SetFocus(hwnd);
9162     ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
9163 
9164     state = GetKeyState(VK_SHIFT);
9165     ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
9166     state = GetKeyState(VK_CAPITAL);
9167     ok(state == 0, "wrong CapsLock state %04x\n", state);
9168 
9169     hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
9170     assert(hAccel != 0);
9171 
9172     flush_events();
9173     pump_msg_loop(hwnd, 0);
9174     flush_sequence();
9175 
9176     trace("testing VK_N press/release\n");
9177     flush_sequence();
9178     keybd_event('N', 0, 0, 0);
9179     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9180     pump_msg_loop(hwnd, hAccel);
9181     if (!sequence_cnt)  /* we didn't get any message */
9182     {
9183         skip( "queuing key events not supported\n" );
9184         goto done;
9185     }
9186     ok_sequence(WmVkN, "VK_N press/release", FALSE);
9187 
9188     trace("testing Shift+VK_N press/release\n");
9189     flush_sequence();
9190     keybd_event(VK_SHIFT, 0, 0, 0);
9191     keybd_event('N', 0, 0, 0);
9192     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9193     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9194     pump_msg_loop(hwnd, hAccel);
9195     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
9196 
9197     trace("testing Ctrl+VK_N press/release\n");
9198     flush_sequence();
9199     keybd_event(VK_CONTROL, 0, 0, 0);
9200     keybd_event('N', 0, 0, 0);
9201     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9202     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9203     pump_msg_loop(hwnd, hAccel);
9204     ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
9205 
9206     trace("testing Alt+VK_N press/release\n");
9207     flush_sequence();
9208     keybd_event(VK_MENU, 0, 0, 0);
9209     keybd_event('N', 0, 0, 0);
9210     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9211     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9212     pump_msg_loop(hwnd, hAccel);
9213     ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
9214 
9215     trace("testing Ctrl+Alt+VK_N press/release 1\n");
9216     flush_sequence();
9217     keybd_event(VK_CONTROL, 0, 0, 0);
9218     keybd_event(VK_MENU, 0, 0, 0);
9219     keybd_event('N', 0, 0, 0);
9220     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9221     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9222     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9223     pump_msg_loop(hwnd, hAccel);
9224     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
9225 
9226     ret = DestroyAcceleratorTable(hAccel);
9227     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
9228 
9229     hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(2));
9230     assert(hAccel != 0);
9231 
9232     trace("testing VK_N press/release\n");
9233     flush_sequence();
9234     keybd_event('N', 0, 0, 0);
9235     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9236     pump_msg_loop(hwnd, hAccel);
9237     ok_sequence(WmVkN, "VK_N press/release", FALSE);
9238 
9239     trace("testing Shift+VK_N press/release\n");
9240     flush_sequence();
9241     keybd_event(VK_SHIFT, 0, 0, 0);
9242     keybd_event('N', 0, 0, 0);
9243     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9244     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9245     pump_msg_loop(hwnd, hAccel);
9246     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
9247 
9248     trace("testing Ctrl+VK_N press/release 2\n");
9249     flush_sequence();
9250     keybd_event(VK_CONTROL, 0, 0, 0);
9251     keybd_event('N', 0, 0, 0);
9252     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9253     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9254     pump_msg_loop(hwnd, hAccel);
9255     ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
9256 
9257     trace("testing Alt+VK_N press/release 2\n");
9258     flush_sequence();
9259     keybd_event(VK_MENU, 0, 0, 0);
9260     keybd_event('N', 0, 0, 0);
9261     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9262     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9263     pump_msg_loop(hwnd, hAccel);
9264     ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
9265 
9266     trace("testing Ctrl+Alt+VK_N press/release 2\n");
9267     flush_sequence();
9268     keybd_event(VK_CONTROL, 0, 0, 0);
9269     keybd_event(VK_MENU, 0, 0, 0);
9270     keybd_event('N', 0, 0, 0);
9271     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9272     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9273     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9274     pump_msg_loop(hwnd, hAccel);
9275     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
9276 
9277     trace("testing Ctrl+Shift+VK_N press/release\n");
9278     flush_sequence();
9279     keybd_event(VK_CONTROL, 0, 0, 0);
9280     keybd_event(VK_SHIFT, 0, 0, 0);
9281     keybd_event('N', 0, 0, 0);
9282     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9283     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9284     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9285     pump_msg_loop(hwnd, hAccel);
9286     ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
9287 
9288     trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
9289     flush_sequence();
9290     keybd_event(VK_CONTROL, 0, 0, 0);
9291     keybd_event(VK_MENU, 0, 0, 0);
9292     keybd_event(VK_SHIFT, 0, 0, 0);
9293     keybd_event('N', 0, 0, 0);
9294     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9295     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9296     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9297     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9298     pump_msg_loop(hwnd, hAccel);
9299     ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
9300 
9301     ret = DestroyAcceleratorTable(hAccel);
9302     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
9303     hAccel = 0;
9304 
9305     trace("testing Alt press/release\n");
9306     flush_sequence();
9307     keybd_event(VK_MENU, 0, 0, 0);
9308     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9309     keybd_event(VK_MENU, 0, 0, 0);
9310     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9311     pump_msg_loop(hwnd, 0);
9312     /* this test doesn't pass in Wine for managed windows */
9313     ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
9314 
9315     trace("testing VK_F1 press/release\n");
9316     keybd_event(VK_F1, 0, 0, 0);
9317     keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
9318     pump_msg_loop(hwnd, 0);
9319     ok_sequence(WmF1Seq, "F1 press/release", FALSE);
9320 
9321     trace("testing VK_APPS press/release\n");
9322     keybd_event(VK_APPS, 0, 0, 0);
9323     keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
9324     pump_msg_loop(hwnd, 0);
9325     ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
9326 
9327     trace("testing VK_F10 press/release\n");
9328     keybd_event(VK_F10, 0, 0, 0);
9329     keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
9330     keybd_event(VK_F10, 0, 0, 0);
9331     keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
9332     pump_msg_loop(hwnd, 0);
9333     ok_sequence(WmVkF10Seq, "VK_F10 press/release", TRUE);
9334 
9335     trace("testing SHIFT+F10 press/release\n");
9336     keybd_event(VK_SHIFT, 0, 0, 0);
9337     keybd_event(VK_F10, 0, 0, 0);
9338     keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
9339     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9340     keybd_event(VK_ESCAPE, 0, 0, 0);
9341     keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
9342     pump_msg_loop(hwnd, 0);
9343     ok_sequence(WmShiftF10Seq, "SHIFT+F10 press/release", TRUE);
9344 
9345     trace("testing Shift+MouseButton press/release\n");
9346     /* first, move mouse pointer inside of the window client area */
9347     GetClientRect(hwnd, &rc);
9348     MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
9349     rc.left += (rc.right - rc.left)/2;
9350     rc.top += (rc.bottom - rc.top)/2;
9351     SetCursorPos(rc.left, rc.top);
9352     SetActiveWindow(hwnd);
9353 
9354     flush_events();
9355     flush_sequence();
9356     GetCursorPos(&pt);
9357     if (pt.x == rc.left && pt.y == rc.top)
9358     {
9359         int i;
9360         keybd_event(VK_SHIFT, 0, 0, 0);
9361         mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
9362         mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
9363         keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9364         pump_msg_loop(hwnd, 0);
9365         for (i = 0; i < sequence_cnt; i++) if (sequence[i].message == WM_LBUTTONDOWN) break;
9366         if (i < sequence_cnt)
9367             ok_sequence(WmShiftMouseButton, "Shift+MouseButton press/release", FALSE);
9368         else
9369             skip( "Shift+MouseButton event didn't get to the window\n" );
9370     }
9371 
9372 done:
9373     if (hAccel) DestroyAcceleratorTable(hAccel);
9374     DestroyWindow(hwnd);
9375 }
9376 
9377 /************* window procedures ********************/
9378 
9379 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message,
9380 			     WPARAM wParam, LPARAM lParam)
9381 {
9382     static LONG defwndproc_counter = 0;
9383     static LONG beginpaint_counter = 0;
9384     LRESULT ret;
9385     struct recvd_message msg;
9386 
9387     if (ignore_message( message )) return 0;
9388 
9389     switch (message)
9390     {
9391 	case WM_ENABLE:
9392 	{
9393 	    LONG style = GetWindowLongA(hwnd, GWL_STYLE);
9394 	    ok((BOOL)wParam == !(style & WS_DISABLED),
9395 		"wrong WS_DISABLED state: %ld != %d\n", wParam, !(style & WS_DISABLED));
9396 	    break;
9397 	}
9398 
9399 	case WM_CAPTURECHANGED:
9400 	    if (test_DestroyWindow_flag)
9401 	    {
9402 		DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
9403 		if (style & WS_CHILD)
9404 		    lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
9405 		else if (style & WS_POPUP)
9406 		    lParam = WND_POPUP_ID;
9407 		else
9408 		    lParam = WND_PARENT_ID;
9409 	    }
9410 	    break;
9411 
9412 	case WM_NCDESTROY:
9413 	{
9414 	    HWND capture;
9415 
9416 	    ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
9417 	    capture = GetCapture();
9418 	    if (capture)
9419 	    {
9420 		ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
9421 		trace("current capture %p, releasing...\n", capture);
9422 		ReleaseCapture();
9423 	    }
9424 	}
9425 	/* fall through */
9426 	case WM_DESTROY:
9427             if (pGetAncestor)
9428 	        ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
9429 	    if (test_DestroyWindow_flag)
9430 	    {
9431 		DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
9432 		if (style & WS_CHILD)
9433 		    lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
9434 		else if (style & WS_POPUP)
9435 		    lParam = WND_POPUP_ID;
9436 		else
9437 		    lParam = WND_PARENT_ID;
9438 	    }
9439 	    break;
9440 
9441 	/* test_accelerators() depends on this */
9442 	case WM_NCHITTEST:
9443 	    return HTCLIENT;
9444 
9445 	case WM_USER+10:
9446 	{
9447 	    ACTIVATION_CONTEXT_BASIC_INFORMATION basicinfo;
9448 	    HANDLE handle, event = (HANDLE)lParam;
9449 	    BOOL ret;
9450 
9451 	    handle = (void*)0xdeadbeef;
9452 	    ret = pGetCurrentActCtx(&handle);
9453 	    ok(ret, "failed to get current context, %u\n", GetLastError());
9454 	    ok(handle == 0, "got active context %p\n", handle);
9455 
9456 	    memset(&basicinfo, 0xff, sizeof(basicinfo));
9457 	    ret = pQueryActCtxW(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX, handle, 0, ActivationContextBasicInformation,
9458 	        &basicinfo, sizeof(basicinfo), NULL);
9459 	    ok(ret, "got %d, error %d\n", ret, GetLastError());
9460 	    ok(basicinfo.hActCtx == NULL, "got %p\n", basicinfo.hActCtx);
9461 	    ok(basicinfo.dwFlags == 0, "got %x\n", basicinfo.dwFlags);
9462 
9463 	    if (event) SetEvent(event);
9464 	    return 1;
9465 	}
9466 
9467 	/* ignore */
9468 	case WM_MOUSEMOVE:
9469 	case WM_MOUSEACTIVATE:
9470 	case WM_NCMOUSEMOVE:
9471 	case WM_SETCURSOR:
9472 	case WM_IME_SELECT:
9473 	    return 0;
9474     }
9475 
9476     msg.hwnd = hwnd;
9477     msg.message = message;
9478     msg.flags = sent|wparam|lparam;
9479     if (defwndproc_counter) msg.flags |= defwinproc;
9480     if (beginpaint_counter) msg.flags |= beginpaint;
9481     msg.wParam = wParam;
9482     msg.lParam = lParam;
9483     msg.descr = "MsgCheckProc";
9484     add_message(&msg);
9485 
9486     if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
9487     {
9488 	HWND parent = GetParent(hwnd);
9489 	RECT rc;
9490 	MINMAXINFO *minmax = (MINMAXINFO *)lParam;
9491 
9492 	GetClientRect(parent, &rc);
9493 	trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
9494         trace("Reserved=%d,%d MaxSize=%d,%d MaxPos=%d,%d MinTrack=%d,%d MaxTrack=%d,%d\n",
9495               minmax->ptReserved.x, minmax->ptReserved.y,
9496               minmax->ptMaxSize.x, minmax->ptMaxSize.y,
9497               minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
9498               minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
9499               minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
9500 
9501 	ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n",
9502 	   minmax->ptMaxSize.x, rc.right);
9503 	ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %d != %d\n",
9504 	   minmax->ptMaxSize.y, rc.bottom);
9505     }
9506 
9507     if (message == WM_PAINT)
9508     {
9509         PAINTSTRUCT ps;
9510         beginpaint_counter++;
9511         BeginPaint( hwnd, &ps );
9512         beginpaint_counter--;
9513         EndPaint( hwnd, &ps );
9514         return 0;
9515     }
9516 
9517     if (message == WM_CONTEXTMENU)
9518     {
9519         /* don't create context menu */
9520         return 0;
9521     }
9522 
9523     defwndproc_counter++;
9524     ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam)
9525 		  : DefWindowProcA(hwnd, message, wParam, lParam);
9526     defwndproc_counter--;
9527 
9528     return ret;
9529 }
9530 
9531 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9532 {
9533     return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
9534 }
9535 
9536 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9537 {
9538     return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
9539 }
9540 
9541 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9542 {
9543     static LONG defwndproc_counter = 0;
9544     LRESULT ret;
9545     struct recvd_message msg;
9546 
9547     if (ignore_message( message )) return 0;
9548 
9549     switch (message)
9550     {
9551     case WM_QUERYENDSESSION:
9552     case WM_ENDSESSION:
9553         lParam &= ~0x01;  /* Vista adds a 0x01 flag */
9554         break;
9555     }
9556 
9557     msg.hwnd = hwnd;
9558     msg.message = message;
9559     msg.flags = sent|wparam|lparam;
9560     if (defwndproc_counter) msg.flags |= defwinproc;
9561     msg.wParam = wParam;
9562     msg.lParam = lParam;
9563     msg.descr = "popup";
9564     add_message(&msg);
9565 
9566     if (message == WM_CREATE)
9567     {
9568 	DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
9569 	SetWindowLongA(hwnd, GWL_STYLE, style);
9570     }
9571 
9572     defwndproc_counter++;
9573     ret = DefWindowProcA(hwnd, message, wParam, lParam);
9574     defwndproc_counter--;
9575 
9576     return ret;
9577 }
9578 
9579 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9580 {
9581     static LONG defwndproc_counter = 0;
9582     static LONG beginpaint_counter = 0;
9583     LRESULT ret;
9584     struct recvd_message msg;
9585 
9586     if (ignore_message( message )) return 0;
9587 
9588     if (log_all_parent_messages ||
9589         message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
9590 	message == WM_SETFOCUS || message == WM_KILLFOCUS ||
9591 	message == WM_ENABLE ||	message == WM_ENTERIDLE ||
9592 	message == WM_DRAWITEM || message == WM_MEASUREITEM || message == WM_COMPAREITEM ||
9593 	message == WM_COMMAND || message == WM_IME_SETCONTEXT)
9594     {
9595         switch (message)
9596         {
9597             /* ignore */
9598             case WM_NCHITTEST:
9599                 return HTCLIENT;
9600             case WM_SETCURSOR:
9601             case WM_MOUSEMOVE:
9602             case WM_NCMOUSEMOVE:
9603                 return 0;
9604 
9605             case WM_ERASEBKGND:
9606             {
9607                 RECT rc;
9608                 INT ret = GetClipBox((HDC)wParam, &rc);
9609 
9610                 trace("WM_ERASEBKGND: GetClipBox()=%d, %s\n", ret, wine_dbgstr_rect(&rc));
9611                 break;
9612             }
9613         }
9614 
9615         msg.hwnd = hwnd;
9616         msg.message = message;
9617         msg.flags = sent|parent|wparam|lparam;
9618         if (defwndproc_counter) msg.flags |= defwinproc;
9619         if (beginpaint_counter) msg.flags |= beginpaint;
9620         msg.wParam = wParam;
9621         msg.lParam = lParam;
9622         msg.descr = "parent";
9623         add_message(&msg);
9624     }
9625 
9626     if (message == WM_PAINT)
9627     {
9628         PAINTSTRUCT ps;
9629         beginpaint_counter++;
9630         BeginPaint( hwnd, &ps );
9631         beginpaint_counter--;
9632         EndPaint( hwnd, &ps );
9633         return 0;
9634     }
9635 
9636     defwndproc_counter++;
9637     ret = DefWindowProcA(hwnd, message, wParam, lParam);
9638     defwndproc_counter--;
9639 
9640     return message == WM_COMPAREITEM ? -1 : ret;
9641 }
9642 
9643 static INT_PTR CALLBACK StopQuitMsgCheckProcA(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
9644 {
9645     if (message == WM_CREATE)
9646         PostMessageA(hwnd, WM_CLOSE, 0, 0);
9647     else if (message == WM_CLOSE)
9648     {
9649         /* Only the first WM_QUIT will survive the window destruction */
9650         PostMessageA(hwnd, WM_USER, 0x1234, 0x5678);
9651         PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
9652         PostMessageA(hwnd, WM_QUIT, 0x4321, 0x8765);
9653     }
9654 
9655     return DefWindowProcA(hwnd, message, wp, lp);
9656 }
9657 
9658 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9659 {
9660     static LONG defwndproc_counter = 0;
9661     LRESULT ret;
9662     struct recvd_message msg;
9663 
9664     if (ignore_message( message )) return 0;
9665 
9666     if (test_def_id)
9667     {
9668         DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
9669         ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
9670         if (after_end_dialog)
9671             ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
9672         else
9673             ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
9674     }
9675 
9676     msg.hwnd = hwnd;
9677     msg.message = message;
9678     msg.flags = sent|wparam|lparam;
9679     if (defwndproc_counter) msg.flags |= defwinproc;
9680     msg.wParam = wParam;
9681     msg.lParam = lParam;
9682     msg.descr = "dialog";
9683     add_message(&msg);
9684 
9685     defwndproc_counter++;
9686     ret = DefDlgProcA(hwnd, message, wParam, lParam);
9687     defwndproc_counter--;
9688 
9689     return ret;
9690 }
9691 
9692 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9693 {
9694     static LONG defwndproc_counter = 0;
9695     LRESULT ret;
9696     struct recvd_message msg;
9697 
9698     /* log only specific messages we are interested in */
9699     switch (message)
9700     {
9701 #if 0 /* probably log these as well */
9702     case WM_ACTIVATE:
9703     case WM_SETFOCUS:
9704     case WM_KILLFOCUS:
9705 #endif
9706     case WM_SHOWWINDOW:
9707     case WM_SIZE:
9708     case WM_MOVE:
9709     case WM_GETMINMAXINFO:
9710     case WM_WINDOWPOSCHANGING:
9711     case WM_WINDOWPOSCHANGED:
9712         break;
9713 
9714     default: /* ignore */
9715         /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
9716         return DefWindowProcA(hwnd, message, wParam, lParam);
9717     }
9718 
9719     msg.hwnd = hwnd;
9720     msg.message = message;
9721     msg.flags = sent|wparam|lparam;
9722     if (defwndproc_counter) msg.flags |= defwinproc;
9723     msg.wParam = wParam;
9724     msg.lParam = lParam;
9725     msg.descr = "show";
9726     add_message(&msg);
9727 
9728     defwndproc_counter++;
9729     ret = DefWindowProcA(hwnd, message, wParam, lParam);
9730     defwndproc_counter--;
9731 
9732     return ret;
9733 }
9734 
9735 static LRESULT WINAPI recursive_activation_wndprocA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9736 {
9737     static LONG defwndproc_counter = 0;
9738     struct recvd_message msg;
9739     LRESULT ret;
9740 
9741     switch (message)
9742     {
9743     /* log only specific messages we are interested in */
9744     case WM_NCACTIVATE:
9745     case WM_ACTIVATE:
9746     case WM_SETFOCUS:
9747     case WM_KILLFOCUS:
9748         break;
9749     default:
9750         return DefWindowProcA(hwnd, message, wParam, lParam);
9751     }
9752 
9753     msg.hwnd = hwnd;
9754     msg.message = message;
9755     msg.flags = sent|wparam|lparam;
9756     if (defwndproc_counter) msg.flags |= defwinproc;
9757     msg.wParam = wParam;
9758     msg.lParam = lParam;
9759     msg.descr = "recursive_activation";
9760     add_message(&msg);
9761 
9762     /* recursively activate ourselves by first losing activation and changing it back */
9763     if (message == WM_ACTIVATE && LOWORD(wParam) != WA_INACTIVE)
9764     {
9765         SetActiveWindow((HWND)lParam);
9766         SetActiveWindow(hwnd);
9767         return 0;
9768     }
9769 
9770     defwndproc_counter++;
9771     ret = DefWindowProcA(hwnd, message, wParam, lParam);
9772     defwndproc_counter--;
9773 
9774     return ret;
9775 }
9776 
9777 static LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
9778 {
9779     switch (msg)
9780     {
9781         case WM_CREATE: return 0;
9782         case WM_PAINT:
9783         {
9784             MSG msg2;
9785             static int i = 0;
9786 
9787             if (i < 256)
9788             {
9789                 i++;
9790                 if (PeekMessageA(&msg2, 0, 0, 0, 1))
9791                 {
9792                     TranslateMessage(&msg2);
9793                     DispatchMessageA(&msg2);
9794                 }
9795                 i--;
9796             }
9797             else ok(broken(1), "infinite loop\n");
9798             if ( i == 0)
9799                 paint_loop_done = TRUE;
9800             return DefWindowProcA(hWnd,msg,wParam,lParam);
9801         }
9802     }
9803     return DefWindowProcA(hWnd,msg,wParam,lParam);
9804 }
9805 
9806 static LRESULT WINAPI HotkeyMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9807 {
9808     static LONG defwndproc_counter = 0;
9809     LRESULT ret;
9810     struct recvd_message msg;
9811     DWORD queue_status;
9812 
9813     if (ignore_message( message )) return 0;
9814 
9815     if ((message >= WM_KEYFIRST && message <= WM_KEYLAST) ||
9816         message == WM_HOTKEY || message >= WM_APP)
9817     {
9818         msg.hwnd = hwnd;
9819         msg.message = message;
9820         msg.flags = sent|wparam|lparam;
9821         if (defwndproc_counter) msg.flags |= defwinproc;
9822         msg.wParam = wParam;
9823         msg.lParam = lParam;
9824         msg.descr = "HotkeyMsgCheckProcA";
9825         add_message(&msg);
9826     }
9827 
9828     defwndproc_counter++;
9829     ret = DefWindowProcA(hwnd, message, wParam, lParam);
9830     defwndproc_counter--;
9831 
9832     if (message == WM_APP)
9833     {
9834         queue_status = GetQueueStatus(QS_HOTKEY);
9835         ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
9836         queue_status = GetQueueStatus(QS_POSTMESSAGE);
9837         ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
9838         PostMessageA(hwnd, WM_APP+1, 0, 0);
9839     }
9840     else if (message == WM_APP+1)
9841     {
9842         queue_status = GetQueueStatus(QS_HOTKEY);
9843         ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
9844     }
9845 
9846     return ret;
9847 }
9848 
9849 static BOOL RegisterWindowClasses(void)
9850 {
9851     WNDCLASSA cls;
9852     WNDCLASSW clsW;
9853 
9854     cls.style = 0;
9855     cls.lpfnWndProc = MsgCheckProcA;
9856     cls.cbClsExtra = 0;
9857     cls.cbWndExtra = 0;
9858     cls.hInstance = GetModuleHandleA(0);
9859     cls.hIcon = 0;
9860     cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
9861     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
9862     cls.lpszMenuName = NULL;
9863     cls.lpszClassName = "TestWindowClass";
9864     if(!RegisterClassA(&cls)) return FALSE;
9865 
9866     cls.lpfnWndProc = HotkeyMsgCheckProcA;
9867     cls.lpszClassName = "HotkeyWindowClass";
9868     if(!RegisterClassA(&cls)) return FALSE;
9869 
9870     cls.lpfnWndProc = ShowWindowProcA;
9871     cls.lpszClassName = "ShowWindowClass";
9872     if(!RegisterClassA(&cls)) return FALSE;
9873 
9874     cls.lpfnWndProc = recursive_activation_wndprocA;
9875     cls.lpszClassName = "RecursiveActivationClass";
9876     if(!RegisterClassA(&cls)) return FALSE;
9877 
9878     cls.lpfnWndProc = PopupMsgCheckProcA;
9879     cls.lpszClassName = "TestPopupClass";
9880     if(!RegisterClassA(&cls)) return FALSE;
9881 
9882     cls.lpfnWndProc = ParentMsgCheckProcA;
9883     cls.lpszClassName = "TestParentClass";
9884     if(!RegisterClassA(&cls)) return FALSE;
9885 
9886     cls.lpfnWndProc = StopQuitMsgCheckProcA;
9887     cls.lpszClassName = "StopQuitClass";
9888     if(!RegisterClassA(&cls)) return FALSE;
9889 
9890     cls.lpfnWndProc = DefWindowProcA;
9891     cls.lpszClassName = "SimpleWindowClass";
9892     if(!RegisterClassA(&cls)) return FALSE;
9893 
9894     cls.lpfnWndProc = PaintLoopProcA;
9895     cls.lpszClassName = "PaintLoopWindowClass";
9896     if(!RegisterClassA(&cls)) return FALSE;
9897 
9898     cls.style = CS_NOCLOSE;
9899     cls.lpszClassName = "NoCloseWindowClass";
9900     if(!RegisterClassA(&cls)) return FALSE;
9901 
9902     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
9903     cls.style = 0;
9904     cls.hInstance = GetModuleHandleA(0);
9905     cls.hbrBackground = 0;
9906     cls.lpfnWndProc = TestDlgProcA;
9907     cls.lpszClassName = "TestDialogClass";
9908     if(!RegisterClassA(&cls)) return FALSE;
9909 
9910     clsW.style = 0;
9911     clsW.lpfnWndProc = MsgCheckProcW;
9912     clsW.cbClsExtra = 0;
9913     clsW.cbWndExtra = 0;
9914     clsW.hInstance = GetModuleHandleW(0);
9915     clsW.hIcon = 0;
9916     clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
9917     clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
9918     clsW.lpszMenuName = NULL;
9919     clsW.lpszClassName = testWindowClassW;
9920     RegisterClassW(&clsW);  /* ignore error, this fails on Win9x */
9921 
9922     return TRUE;
9923 }
9924 
9925 static BOOL is_our_logged_class(HWND hwnd)
9926 {
9927     char buf[256];
9928 
9929     if (GetClassNameA(hwnd, buf, sizeof(buf)))
9930     {
9931 	if (!lstrcmpiA(buf, "TestWindowClass") ||
9932 	    !lstrcmpiA(buf, "ShowWindowClass") ||
9933 	    !lstrcmpiA(buf, "RecursiveActivationClass") ||
9934 	    !lstrcmpiA(buf, "TestParentClass") ||
9935 	    !lstrcmpiA(buf, "TestPopupClass") ||
9936 	    !lstrcmpiA(buf, "SimpleWindowClass") ||
9937 	    !lstrcmpiA(buf, "TestDialogClass") ||
9938 	    !lstrcmpiA(buf, "MDI_frame_class") ||
9939 	    !lstrcmpiA(buf, "MDI_client_class") ||
9940 	    !lstrcmpiA(buf, "MDI_child_class") ||
9941 	    !lstrcmpiA(buf, "my_button_class") ||
9942 	    !lstrcmpiA(buf, "my_edit_class") ||
9943 	    !lstrcmpiA(buf, "static") ||
9944 	    !lstrcmpiA(buf, "ListBox") ||
9945 	    !lstrcmpiA(buf, "ComboBox") ||
9946 	    !lstrcmpiA(buf, "MyDialogClass") ||
9947 	    !lstrcmpiA(buf, "#32770") ||
9948 	    !lstrcmpiA(buf, "#32768"))
9949         return TRUE;
9950     }
9951     return FALSE;
9952 }
9953 
9954 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
9955 {
9956     HWND hwnd;
9957 
9958     ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
9959 
9960     if (nCode == HCBT_CLICKSKIPPED)
9961     {
9962         /* ignore this event, XP sends it a lot when switching focus between windows */
9963 	return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
9964     }
9965 
9966     if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
9967     {
9968 	struct recvd_message msg;
9969 
9970         msg.hwnd = 0;
9971 	msg.message = nCode;
9972 	msg.flags = hook|wparam|lparam;
9973 	msg.wParam = wParam;
9974 	msg.lParam = lParam;
9975         msg.descr = "CBT";
9976 	add_message(&msg);
9977 
9978 	return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
9979     }
9980 
9981     if (nCode == HCBT_DESTROYWND)
9982     {
9983 	if (test_DestroyWindow_flag)
9984 	{
9985 	    DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
9986 	    if (style & WS_CHILD)
9987 		lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
9988 	    else if (style & WS_POPUP)
9989 		lParam = WND_POPUP_ID;
9990 	    else
9991 		lParam = WND_PARENT_ID;
9992 	}
9993     }
9994 
9995     /* Log also SetFocus(0) calls */
9996     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
9997 
9998     if (is_our_logged_class(hwnd))
9999     {
10000         struct recvd_message msg;
10001 
10002         msg.hwnd = hwnd;
10003         msg.message = nCode;
10004         msg.flags = hook|wparam|lparam;
10005         msg.wParam = wParam;
10006         msg.lParam = lParam;
10007         msg.descr = "CBT";
10008         add_message(&msg);
10009     }
10010     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
10011 }
10012 
10013 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
10014 				    DWORD event,
10015 				    HWND hwnd,
10016 				    LONG object_id,
10017 				    LONG child_id,
10018 				    DWORD thread_id,
10019 				    DWORD event_time)
10020 {
10021     ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
10022 
10023     /* ignore mouse cursor events */
10024     if (object_id == OBJID_CURSOR) return;
10025 
10026     if (!hwnd || is_our_logged_class(hwnd))
10027     {
10028         struct recvd_message msg;
10029 
10030         msg.hwnd = hwnd;
10031         msg.message = event;
10032         msg.flags = winevent_hook|wparam|lparam;
10033         msg.wParam = object_id;
10034         msg.lParam = child_id;
10035         msg.descr = "WEH";
10036         add_message(&msg);
10037     }
10038 }
10039 
10040 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
10041 static const WCHAR wszAnsi[] = {'U',0};
10042 
10043 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
10044 {
10045     switch (uMsg)
10046     {
10047     case CB_FINDSTRINGEXACT:
10048         trace("String: %p\n", (LPCWSTR)lParam);
10049         if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
10050             return 1;
10051         if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
10052             return 0;
10053         return -1;
10054     }
10055     return DefWindowProcW(hwnd, uMsg, wParam, lParam);
10056 }
10057 
10058 static const struct message WmGetTextLengthAfromW[] = {
10059     { WM_GETTEXTLENGTH, sent },
10060     { WM_GETTEXT, sent|optional },
10061     { 0 }
10062 };
10063 
10064 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
10065 
10066 /* dummy window proc for WM_GETTEXTLENGTH test */
10067 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
10068 {
10069     switch(msg)
10070     {
10071     case WM_GETTEXTLENGTH:
10072         return lstrlenW(dummy_window_text) + 37;  /* some random length */
10073     case WM_GETTEXT:
10074         lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
10075         return lstrlenW( (LPWSTR)lp );
10076     default:
10077         return DefWindowProcW( hwnd, msg, wp, lp );
10078     }
10079 }
10080 
10081 static void test_message_conversion(void)
10082 {
10083     static const WCHAR wszMsgConversionClass[] =
10084         {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
10085     WNDCLASSW cls;
10086     LRESULT lRes;
10087     HWND hwnd;
10088     WNDPROC wndproc, newproc;
10089     BOOL ret;
10090 
10091     cls.style = 0;
10092     cls.lpfnWndProc = MsgConversionProcW;
10093     cls.cbClsExtra = 0;
10094     cls.cbWndExtra = 0;
10095     cls.hInstance = GetModuleHandleW(NULL);
10096     cls.hIcon = NULL;
10097     cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
10098     cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
10099     cls.lpszMenuName = NULL;
10100     cls.lpszClassName = wszMsgConversionClass;
10101     /* this call will fail on Win9x, but that doesn't matter as this test is
10102      * meaningless on those platforms */
10103     if(!RegisterClassW(&cls)) return;
10104 
10105     hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
10106                            100, 100, 200, 200, 0, 0, 0, NULL);
10107     ok(hwnd != NULL, "Window creation failed\n");
10108 
10109     /* {W, A} -> A */
10110 
10111     wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
10112     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10113     ok(lRes == 0, "String should have been converted\n");
10114     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10115     ok(lRes == 1, "String shouldn't have been converted\n");
10116 
10117     /* {W, A} -> W */
10118 
10119     wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
10120     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10121     ok(lRes == 1, "String shouldn't have been converted\n");
10122     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10123     ok(lRes == 1, "String shouldn't have been converted\n");
10124 
10125     /* Synchronous messages */
10126 
10127     lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10128     ok(lRes == 0, "String should have been converted\n");
10129     lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10130     ok(lRes == 1, "String shouldn't have been converted\n");
10131 
10132     /* Asynchronous messages */
10133 
10134     SetLastError(0);
10135     lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10136     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10137         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10138     SetLastError(0);
10139     lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10140     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10141         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10142     SetLastError(0);
10143     lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10144     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10145         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10146     SetLastError(0);
10147     lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10148     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10149         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10150     SetLastError(0);
10151     lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10152     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10153         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10154     SetLastError(0);
10155     lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10156     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10157         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10158     SetLastError(0);
10159     lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
10160     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10161         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10162     SetLastError(0);
10163     lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
10164     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10165         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10166 
10167     /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
10168 
10169     hwnd = CreateWindowW (testWindowClassW, wszUnicode,
10170                           WS_OVERLAPPEDWINDOW,
10171                           100, 100, 200, 200, 0, 0, 0, NULL);
10172     assert(hwnd);
10173     flush_sequence();
10174     lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
10175     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
10176     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
10177         "got bad length %ld\n", lRes );
10178 
10179     flush_sequence();
10180     lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
10181                             hwnd, WM_GETTEXTLENGTH, 0, 0);
10182     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
10183     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
10184         "got bad length %ld\n", lRes );
10185 
10186     wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
10187     newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
10188     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
10189     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
10190                                      NULL, 0, NULL, NULL ) ||
10191         broken(lRes == lstrlenW(dummy_window_text) + 37),
10192         "got bad length %ld\n", lRes );
10193 
10194     SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc );  /* restore old wnd proc */
10195     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
10196     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
10197                                      NULL, 0, NULL, NULL ) ||
10198         broken(lRes == lstrlenW(dummy_window_text) + 37),
10199         "got bad length %ld\n", lRes );
10200 
10201     ret = DestroyWindow(hwnd);
10202     ok( ret, "DestroyWindow() error %d\n", GetLastError());
10203 }
10204 
10205 struct timer_info
10206 {
10207     HWND hWnd;
10208     HANDLE handles[2];
10209     DWORD id;
10210 };
10211 
10212 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
10213 {
10214 }
10215 
10216 #define TIMER_ID               0x19
10217 #define TIMER_COUNT_EXPECTED   100
10218 #define TIMER_COUNT_TOLERANCE  10
10219 
10220 static int count = 0;
10221 static void CALLBACK callback_count(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
10222 {
10223     count++;
10224 }
10225 
10226 static DWORD exception;
10227 static void CALLBACK callback_exception(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
10228 {
10229     count++;
10230     RaiseException(exception, 0, 0, NULL);
10231 }
10232 
10233 static DWORD WINAPI timer_thread_proc(LPVOID x)
10234 {
10235     struct timer_info *info = x;
10236     DWORD r;
10237 
10238     r = KillTimer(info->hWnd, 0x19);
10239     ok(r,"KillTimer failed in thread\n");
10240     r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
10241     ok(r,"SetTimer failed in thread\n");
10242     ok(r==TIMER_ID,"SetTimer id different\n");
10243     r = SetEvent(info->handles[0]);
10244     ok(r,"SetEvent failed in thread\n");
10245     return 0;
10246 }
10247 
10248 static void test_timers(void)
10249 {
10250     struct timer_info info;
10251     DWORD start;
10252     DWORD id;
10253     MSG msg;
10254 
10255     info.hWnd = CreateWindowA("TestWindowClass", NULL,
10256        WS_OVERLAPPEDWINDOW ,
10257        CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
10258        NULL, NULL, 0);
10259 
10260     info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
10261     ok(info.id, "SetTimer failed\n");
10262     ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
10263     info.handles[0] = CreateEventW(NULL,0,0,NULL);
10264     info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
10265 
10266     WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
10267 
10268     WaitForSingleObject(info.handles[1], INFINITE);
10269 
10270     CloseHandle(info.handles[0]);
10271     CloseHandle(info.handles[1]);
10272 
10273     ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
10274 
10275     /* Check the minimum allowed timeout for a timer.  MSDN indicates that it should be 10.0 ms,
10276      * which occurs sometimes, but most testing on the VMs indicates a minimum timeout closer to
10277      * 15.6 ms.  Since there is some measurement error between test runs we are allowing for
10278      * ±9 counts (~4 ms) around the expected value.
10279      */
10280     count = 0;
10281     id = SetTimer(info.hWnd, TIMER_ID, 0, callback_count);
10282     ok(id != 0, "did not get id from SetTimer.\n");
10283     ok(id==TIMER_ID, "SetTimer timer ID different\n");
10284     start = GetTickCount();
10285     while (GetTickCount()-start < 1001 && GetMessageA(&msg, info.hWnd, 0, 0))
10286         DispatchMessageA(&msg);
10287 ros_skip_flaky
10288 todo_wine
10289     ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE /* xp */
10290        || broken(abs(count-64) < TIMER_COUNT_TOLERANCE) /* most common */
10291        || broken(abs(count-43) < TIMER_COUNT_TOLERANCE) /* w2k3, win8 */,
10292        "did not get expected count for minimum timeout (%d != ~%d).\n",
10293        count, TIMER_COUNT_EXPECTED);
10294     ok(KillTimer(info.hWnd, id), "KillTimer failed\n");
10295     /* Perform the same check on SetSystemTimer (only available on w2k3 and older) */
10296     if (pSetSystemTimer)
10297     {
10298         int syscount = 0;
10299 
10300         count = 0;
10301         id = pSetSystemTimer(info.hWnd, TIMER_ID, 0, callback_count);
10302         ok(id != 0, "did not get id from SetSystemTimer.\n");
10303         ok(id==TIMER_ID, "SetTimer timer ID different\n");
10304         start = GetTickCount();
10305         while (GetTickCount()-start < 1001 && GetMessageA(&msg, info.hWnd, 0, 0))
10306         {
10307             if (msg.message == WM_SYSTIMER)
10308                 syscount++;
10309             DispatchMessageA(&msg);
10310         }
10311         ok(abs(syscount-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE
10312            || broken(abs(syscount-64) < TIMER_COUNT_TOLERANCE) /* most common */
10313            || broken(syscount > 4000 && syscount < 12000) /* win2k3sp0 */,
10314            "did not get expected count for minimum timeout (%d != ~%d).\n",
10315            syscount, TIMER_COUNT_EXPECTED);
10316         todo_wine ok(count == 0, "did not get expected count for callback timeout (%d != 0).\n",
10317                                  count);
10318         ok(pKillSystemTimer(info.hWnd, id), "KillSystemTimer failed\n");
10319     }
10320 
10321     ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
10322 }
10323 
10324 static void test_timers_no_wnd(void)
10325 {
10326     static UINT_PTR ids[0xffff];
10327     UINT_PTR id, id2;
10328     DWORD start;
10329     MSG msg;
10330     int i;
10331 
10332     count = 0;
10333     id = SetTimer(NULL, 0, 100, callback_count);
10334     ok(id != 0, "did not get id from SetTimer.\n");
10335     id2 = SetTimer(NULL, id, 200, callback_count);
10336     ok(id2 == id, "did not get same id from SetTimer when replacing (%li expected %li).\n", id2, id);
10337     Sleep(150);
10338     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
10339     ok(count == 0, "did not get zero count as expected (%i).\n", count);
10340     Sleep(150);
10341     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
10342     ok(count == 1, "did not get one count as expected (%i).\n", count);
10343     KillTimer(NULL, id);
10344     Sleep(250);
10345     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
10346     ok(count == 1, "killing replaced timer did not work (%i).\n", count);
10347 
10348     /* Check the minimum allowed timeout for a timer.  MSDN indicates that it should be 10.0 ms,
10349      * which occurs sometimes, but most testing on the VMs indicates a minimum timeout closer to
10350      * 15.6 ms.  Since there is some measurement error between test runs we are allowing for
10351      * ±9 counts (~4 ms) around the expected value.
10352      */
10353     count = 0;
10354     id = SetTimer(NULL, 0, 0, callback_count);
10355     ok(id != 0, "did not get id from SetTimer.\n");
10356     start = GetTickCount();
10357     while (GetTickCount()-start < 1001 && GetMessageA(&msg, NULL, 0, 0))
10358         DispatchMessageA(&msg);
10359 todo_wine
10360     ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE /* xp */
10361        || broken(abs(count-64) < TIMER_COUNT_TOLERANCE) /* most common */,
10362        "did not get expected count for minimum timeout (%d != ~%d).\n",
10363        count, TIMER_COUNT_EXPECTED);
10364     KillTimer(NULL, id);
10365     /* Note: SetSystemTimer doesn't support a NULL window, see test_timers */
10366 
10367     if (pSetCoalescableTimer)
10368     {
10369         count = 0;
10370         id = pSetCoalescableTimer(NULL, 0, 0, callback_count, 0);
10371         ok(id != 0, "SetCoalescableTimer failed with %u.\n", GetLastError());
10372         start = GetTickCount();
10373         while (GetTickCount()-start < 100 && GetMessageA(&msg, NULL, 0, 0))
10374             DispatchMessageA(&msg);
10375         ok(count > 1, "expected count > 1, got %d.\n", count);
10376         KillTimer(NULL, id);
10377     }
10378     else
10379         win_skip("SetCoalescableTimer not available.\n");
10380 
10381     /* Check what happens when we're running out of timers */
10382     for (i = 0; i < ARRAY_SIZE(ids); i++)
10383     {
10384         SetLastError(0xdeadbeef);
10385         ids[i] = SetTimer(NULL, 0, USER_TIMER_MAXIMUM, tfunc);
10386         if (!ids[i]) break;
10387     }
10388     ok(i != ARRAY_SIZE(ids), "all timers were created successfully\n");
10389     ok(GetLastError()==ERROR_NO_MORE_USER_HANDLES || broken(GetLastError()==0xdeadbeef),
10390             "GetLastError() = %d\n", GetLastError());
10391     while (i > 0) KillTimer(NULL, ids[--i]);
10392 }
10393 
10394 static void test_timers_exception(DWORD code)
10395 {
10396     UINT_PTR id;
10397     MSG msg;
10398 
10399     exception = code;
10400     id = SetTimer(NULL, 0, 1000, callback_exception);
10401     ok(id != 0, "did not get id from SetTimer.\n");
10402 
10403     memset(&msg, 0, sizeof(msg));
10404     msg.message = WM_TIMER;
10405     msg.wParam = id;
10406     msg.lParam = (LPARAM)callback_exception;
10407 
10408     count = 0;
10409     DispatchMessageA(&msg);
10410     ok(count == 1, "did not get one count as expected (%i).\n", count);
10411 
10412     KillTimer(NULL, id);
10413 }
10414 
10415 static void test_timers_exceptions(void)
10416 {
10417     test_timers_exception(EXCEPTION_ACCESS_VIOLATION);
10418     test_timers_exception(EXCEPTION_DATATYPE_MISALIGNMENT);
10419     test_timers_exception(EXCEPTION_BREAKPOINT);
10420     test_timers_exception(EXCEPTION_SINGLE_STEP);
10421     test_timers_exception(EXCEPTION_ARRAY_BOUNDS_EXCEEDED);
10422     test_timers_exception(EXCEPTION_FLT_DENORMAL_OPERAND);
10423     test_timers_exception(EXCEPTION_FLT_DIVIDE_BY_ZERO);
10424     test_timers_exception(EXCEPTION_FLT_INEXACT_RESULT);
10425     test_timers_exception(EXCEPTION_ILLEGAL_INSTRUCTION);
10426     test_timers_exception(0xE000BEEF); /* customer exception */
10427 }
10428 
10429 /* Various win events with arbitrary parameters */
10430 static const struct message WmWinEventsSeq[] = {
10431     { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
10432     { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
10433     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
10434     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
10435     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
10436     { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
10437     { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
10438     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
10439     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
10440     /* our win event hook ignores OBJID_CURSOR events */
10441     /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
10442     { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
10443     { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
10444     { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
10445     { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
10446     { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
10447     { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
10448     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
10449     { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
10450     { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
10451     { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
10452     { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
10453     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
10454     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
10455     { 0 }
10456 };
10457 static const struct message WmWinEventCaretSeq[] = {
10458     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
10459     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
10460     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
10461     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
10462     { 0 }
10463 };
10464 static const struct message WmWinEventCaretSeq_2[] = {
10465     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
10466     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
10467     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
10468     { 0 }
10469 };
10470 static const struct message WmWinEventAlertSeq[] = {
10471     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
10472     { 0 }
10473 };
10474 static const struct message WmWinEventAlertSeq_2[] = {
10475     /* create window in the thread proc */
10476     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
10477     /* our test event */
10478     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
10479     { 0 }
10480 };
10481 static const struct message WmGlobalHookSeq_1[] = {
10482     /* create window in the thread proc */
10483     { HCBT_CREATEWND, hook|lparam, 0, 2 },
10484     /* our test events */
10485     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
10486     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
10487     { 0 }
10488 };
10489 static const struct message WmGlobalHookSeq_2[] = {
10490     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
10491     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
10492     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
10493     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
10494     { 0 }
10495 };
10496 
10497 static const struct message WmMouseLLHookSeq[] = {
10498     { WM_MOUSEMOVE, hook },
10499     { WM_LBUTTONUP, hook },
10500     { WM_MOUSEMOVE, hook },
10501     { 0 }
10502 };
10503 
10504 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
10505 					 DWORD event,
10506 					 HWND hwnd,
10507 					 LONG object_id,
10508 					 LONG child_id,
10509 					 DWORD thread_id,
10510 					 DWORD event_time)
10511 {
10512     char buf[256];
10513 
10514     if (GetClassNameA(hwnd, buf, sizeof(buf)))
10515     {
10516 	if (!lstrcmpiA(buf, "TestWindowClass") ||
10517 	    !lstrcmpiA(buf, "static"))
10518 	{
10519 	    struct recvd_message msg;
10520 
10521             msg.hwnd = hwnd;
10522 	    msg.message = event;
10523 	    msg.flags = winevent_hook|wparam|lparam;
10524 	    msg.wParam = object_id;
10525 	    msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
10526             msg.descr = "WEH_2";
10527 	    add_message(&msg);
10528 	}
10529     }
10530 }
10531 
10532 static HHOOK hCBT_global_hook;
10533 static DWORD cbt_global_hook_thread_id;
10534 
10535 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
10536 {
10537     HWND hwnd;
10538     char buf[256];
10539 
10540     if (nCode == HCBT_SYSCOMMAND)
10541     {
10542 	struct recvd_message msg;
10543 
10544         msg.hwnd = 0;
10545 	msg.message = nCode;
10546 	msg.flags = hook|wparam|lparam;
10547 	msg.wParam = wParam;
10548 	msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
10549         msg.descr = "CBT_2";
10550 	add_message(&msg);
10551 
10552 	return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
10553     }
10554     /* WH_MOUSE_LL hook */
10555     if (nCode == HC_ACTION)
10556     {
10557         MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
10558 
10559         /* we can't test for real mouse events */
10560         if (mhll->flags & LLMHF_INJECTED)
10561         {
10562 	    struct recvd_message msg;
10563 
10564 	    memset (&msg, 0, sizeof (msg));
10565 	    msg.message = wParam;
10566 	    msg.flags = hook;
10567             msg.descr = "CBT_2";
10568 	    add_message(&msg);
10569         }
10570 	return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
10571     }
10572 
10573     /* Log also SetFocus(0) calls */
10574     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
10575 
10576     if (GetClassNameA(hwnd, buf, sizeof(buf)))
10577     {
10578 	if (!lstrcmpiA(buf, "TestWindowClass") ||
10579 	    !lstrcmpiA(buf, "static"))
10580 	{
10581 	    struct recvd_message msg;
10582 
10583             msg.hwnd = hwnd;
10584 	    msg.message = nCode;
10585 	    msg.flags = hook|wparam|lparam;
10586 	    msg.wParam = wParam;
10587 	    msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
10588             msg.descr = "CBT_2";
10589 	    add_message(&msg);
10590 	}
10591     }
10592     return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
10593 }
10594 
10595 static DWORD WINAPI win_event_global_thread_proc(void *param)
10596 {
10597     HWND hwnd;
10598     MSG msg;
10599     HANDLE hevent = *(HANDLE *)param;
10600 
10601     assert(pNotifyWinEvent);
10602 
10603     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
10604     assert(hwnd);
10605     trace("created thread window %p\n", hwnd);
10606 
10607     *(HWND *)param = hwnd;
10608 
10609     flush_sequence();
10610     /* this event should be received only by our new hook proc,
10611      * an old one does not expect an event from another thread.
10612      */
10613     pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
10614     SetEvent(hevent);
10615 
10616     while (GetMessageA(&msg, 0, 0, 0))
10617     {
10618 	TranslateMessage(&msg);
10619 	DispatchMessageA(&msg);
10620     }
10621     return 0;
10622 }
10623 
10624 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
10625 {
10626     HWND hwnd;
10627     MSG msg;
10628     HANDLE hevent = *(HANDLE *)param;
10629 
10630     flush_sequence();
10631     /* these events should be received only by our new hook proc,
10632      * an old one does not expect an event from another thread.
10633      */
10634 
10635     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
10636     assert(hwnd);
10637     trace("created thread window %p\n", hwnd);
10638 
10639     *(HWND *)param = hwnd;
10640 
10641     /* Windows doesn't like when a thread plays games with the focus,
10642        that leads to all kinds of misbehaviours and failures to activate
10643        a window. So, better keep next lines commented out.
10644     SetFocus(0);
10645     SetFocus(hwnd);*/
10646 
10647     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
10648     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
10649 
10650     SetEvent(hevent);
10651 
10652     while (GetMessageA(&msg, 0, 0, 0))
10653     {
10654 	TranslateMessage(&msg);
10655 	DispatchMessageA(&msg);
10656     }
10657     return 0;
10658 }
10659 
10660 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
10661 {
10662     HWND hwnd;
10663     MSG msg;
10664     HANDLE hevent = *(HANDLE *)param;
10665 
10666     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
10667     assert(hwnd);
10668     trace("created thread window %p\n", hwnd);
10669 
10670     *(HWND *)param = hwnd;
10671 
10672     flush_sequence();
10673 
10674     /* Windows doesn't like when a thread plays games with the focus,
10675      * that leads to all kinds of misbehaviours and failures to activate
10676      * a window. So, better don't generate a mouse click message below.
10677      */
10678     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10679     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
10680     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10681 
10682     SetEvent(hevent);
10683     while (GetMessageA(&msg, 0, 0, 0))
10684     {
10685         TranslateMessage(&msg);
10686         DispatchMessageA(&msg);
10687     }
10688     return 0;
10689 }
10690 
10691 static void test_winevents(void)
10692 {
10693     BOOL ret;
10694     MSG msg;
10695     HWND hwnd, hwnd2;
10696     UINT i;
10697     HANDLE hthread, hevent;
10698     DWORD tid;
10699     HWINEVENTHOOK hhook;
10700     const struct message *events = WmWinEventsSeq;
10701 
10702     hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
10703 			   WS_OVERLAPPEDWINDOW,
10704 			   CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
10705 			   NULL, NULL, 0);
10706     assert(hwnd);
10707 
10708     /****** start of global hook test *************/
10709     hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
10710     if (!hCBT_global_hook)
10711     {
10712         ok(DestroyWindow(hwnd), "failed to destroy window\n");
10713         skip( "cannot set global hook\n" );
10714         return;
10715     }
10716 
10717     hevent = CreateEventA(NULL, 0, 0, NULL);
10718     assert(hevent);
10719     hwnd2 = hevent;
10720 
10721     hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
10722     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
10723 
10724     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10725 
10726     ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
10727 
10728     flush_sequence();
10729     /* this one should be received only by old hook proc */
10730     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
10731     /* this one should be received only by old hook proc */
10732     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
10733 
10734     ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
10735 
10736     ret = UnhookWindowsHookEx(hCBT_global_hook);
10737     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
10738 
10739     PostThreadMessageA(tid, WM_QUIT, 0, 0);
10740     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10741     CloseHandle(hthread);
10742     CloseHandle(hevent);
10743     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10744     /****** end of global hook test *************/
10745 
10746     if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
10747     {
10748 	ok(DestroyWindow(hwnd), "failed to destroy window\n");
10749 	return;
10750     }
10751 
10752     flush_sequence();
10753 
10754     if (0)
10755     {
10756     /* this test doesn't pass under Win9x */
10757     /* win2k ignores events with hwnd == 0 */
10758     SetLastError(0xdeadbeef);
10759     pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
10760     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
10761        GetLastError() == 0xdeadbeef, /* Win9x */
10762        "unexpected error %d\n", GetLastError());
10763     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
10764     }
10765 
10766     for (i = 0; i < ARRAY_SIZE(WmWinEventsSeq); i++)
10767 	pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
10768 
10769     ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
10770 
10771     /****** start of event filtering test *************/
10772     hhook = pSetWinEventHook(
10773 	EVENT_OBJECT_SHOW, /* 0x8002 */
10774 	EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
10775 	GetModuleHandleA(0), win_event_global_hook_proc,
10776 	GetCurrentProcessId(), 0,
10777 	WINEVENT_INCONTEXT);
10778     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
10779 
10780     hevent = CreateEventA(NULL, 0, 0, NULL);
10781     assert(hevent);
10782     hwnd2 = hevent;
10783 
10784     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
10785     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
10786 
10787     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10788 
10789     ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
10790 
10791     flush_sequence();
10792     /* this one should be received only by old hook proc */
10793     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
10794     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
10795     /* this one should be received only by old hook proc */
10796     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
10797 
10798     ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
10799 
10800     ret = pUnhookWinEvent(hhook);
10801     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10802 
10803     PostThreadMessageA(tid, WM_QUIT, 0, 0);
10804     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10805     CloseHandle(hthread);
10806     CloseHandle(hevent);
10807     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10808     /****** end of event filtering test *************/
10809 
10810     /****** start of out of context event test *************/
10811     hhook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0,
10812         win_event_global_hook_proc, GetCurrentProcessId(), 0,
10813 	WINEVENT_OUTOFCONTEXT);
10814     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
10815 
10816     hevent = CreateEventA(NULL, 0, 0, NULL);
10817     assert(hevent);
10818     hwnd2 = hevent;
10819 
10820     flush_sequence();
10821 
10822     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
10823     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
10824 
10825     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10826 
10827     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
10828     /* process pending winevent messages */
10829     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
10830     ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
10831 
10832     flush_sequence();
10833     /* this one should be received only by old hook proc */
10834     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
10835     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
10836     /* this one should be received only by old hook proc */
10837     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
10838 
10839     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
10840     /* process pending winevent messages */
10841     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
10842     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
10843 
10844     ret = pUnhookWinEvent(hhook);
10845     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10846 
10847     PostThreadMessageA(tid, WM_QUIT, 0, 0);
10848     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10849     CloseHandle(hthread);
10850     CloseHandle(hevent);
10851     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10852     /****** end of out of context event test *************/
10853 
10854     /****** start of MOUSE_LL hook test *************/
10855     hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
10856     /* WH_MOUSE_LL is not supported on Win9x platforms */
10857     if (!hCBT_global_hook)
10858     {
10859         win_skip("Skipping WH_MOUSE_LL test on this platform\n");
10860         goto skip_mouse_ll_hook_test;
10861     }
10862 
10863     hevent = CreateEventA(NULL, 0, 0, NULL);
10864     assert(hevent);
10865     hwnd2 = hevent;
10866 
10867     hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
10868     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
10869 
10870     while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
10871         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
10872 
10873     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
10874     flush_sequence();
10875 
10876     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10877     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
10878     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10879 
10880     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
10881 
10882     ret = UnhookWindowsHookEx(hCBT_global_hook);
10883     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
10884 
10885     PostThreadMessageA(tid, WM_QUIT, 0, 0);
10886     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10887     CloseHandle(hthread);
10888     CloseHandle(hevent);
10889     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10890     /****** end of MOUSE_LL hook test *************/
10891 skip_mouse_ll_hook_test:
10892 
10893     ok(DestroyWindow(hwnd), "failed to destroy window\n");
10894 }
10895 
10896 static void test_set_hook(void)
10897 {
10898     BOOL ret;
10899     HHOOK hhook;
10900     HWINEVENTHOOK hwinevent_hook;
10901 
10902     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
10903     ok(hhook != 0, "local hook does not require hModule set to 0\n");
10904     UnhookWindowsHookEx(hhook);
10905 
10906     if (0)
10907     {
10908     /* this test doesn't pass under Win9x: BUG! */
10909     SetLastError(0xdeadbeef);
10910     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
10911     ok(!hhook, "global hook requires hModule != 0\n");
10912     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
10913     }
10914 
10915     SetLastError(0xdeadbeef);
10916     hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
10917     ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
10918     ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
10919        GetLastError() == 0xdeadbeef, /* Win9x */
10920        "unexpected error %d\n", GetLastError());
10921 
10922     SetLastError(0xdeadbeef);
10923     ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
10924     ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
10925        GetLastError() == 0xdeadbeef, /* Win9x */
10926        "unexpected error %d\n", GetLastError());
10927 
10928     if (!pSetWinEventHook || !pUnhookWinEvent) return;
10929 
10930     /* even process local incontext hooks require hmodule */
10931     SetLastError(0xdeadbeef);
10932     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10933         GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
10934     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
10935     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
10936        GetLastError() == 0xdeadbeef, /* Win9x */
10937        "unexpected error %d\n", GetLastError());
10938 
10939     /* even thread local incontext hooks require hmodule */
10940     SetLastError(0xdeadbeef);
10941     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10942         GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
10943     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
10944     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
10945        GetLastError() == 0xdeadbeef, /* Win9x */
10946        "unexpected error %d\n", GetLastError());
10947 
10948     if (0)
10949     {
10950     /* these 3 tests don't pass under Win9x */
10951     SetLastError(0xdeadbeef);
10952     hwinevent_hook = pSetWinEventHook(1, 0, 0, win_event_proc,
10953         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
10954     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
10955     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
10956 
10957     SetLastError(0xdeadbeef);
10958     hwinevent_hook = pSetWinEventHook(-1, 1, 0, win_event_proc,
10959         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
10960     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
10961     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
10962 
10963     SetLastError(0xdeadbeef);
10964     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10965         0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
10966     ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
10967     ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
10968     }
10969 
10970     SetLastError(0xdeadbeef);
10971     hwinevent_hook = pSetWinEventHook(0, 0, 0, win_event_proc,
10972         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
10973     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
10974     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
10975     ret = pUnhookWinEvent(hwinevent_hook);
10976     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10977 
10978 todo_wine {
10979     /* This call succeeds under win2k SP4, but fails under Wine.
10980        Does win2k test/use passed process id? */
10981     SetLastError(0xdeadbeef);
10982     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10983         0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
10984     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
10985     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
10986     ret = pUnhookWinEvent(hwinevent_hook);
10987     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10988 }
10989 
10990     SetLastError(0xdeadbeef);
10991     ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
10992     ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
10993 	GetLastError() == 0xdeadbeef, /* Win9x */
10994 	"unexpected error %d\n", GetLastError());
10995 }
10996 
10997 static HWND hook_hwnd;
10998 static HHOOK recursive_hook;
10999 static int hook_depth, max_hook_depth;
11000 
11001 static LRESULT WINAPI rec_get_message_hook(int code, WPARAM w, LPARAM l)
11002 {
11003     LRESULT res;
11004     MSG msg;
11005     BOOL b;
11006 
11007     hook_depth++;
11008     if(hook_depth > max_hook_depth)
11009         max_hook_depth = hook_depth;
11010 
11011     b = PeekMessageW(&msg, hook_hwnd, 0, 0, PM_NOREMOVE);
11012     ok(b, "PeekMessage failed\n");
11013 
11014     res = CallNextHookEx(recursive_hook, code, w, l);
11015 
11016     hook_depth--;
11017     return res;
11018 }
11019 
11020 static void test_recursive_hook(void)
11021 {
11022     MSG msg;
11023     BOOL b;
11024 
11025     hook_hwnd = CreateWindowA("Static", NULL, WS_POPUP, 0, 0, 200, 60, NULL, NULL, NULL, NULL);
11026     ok(hook_hwnd != NULL, "CreateWindow failed\n");
11027 
11028     recursive_hook = SetWindowsHookExW(WH_GETMESSAGE, rec_get_message_hook, NULL, GetCurrentThreadId());
11029     ok(recursive_hook != NULL, "SetWindowsHookEx failed\n");
11030 
11031     PostMessageW(hook_hwnd, WM_USER, 0, 0);
11032     PostMessageW(hook_hwnd, WM_USER+1, 0, 0);
11033 
11034     hook_depth = 0;
11035     GetMessageW(&msg, hook_hwnd, 0, 0);
11036     ok(15 <= max_hook_depth && max_hook_depth < 45, "max_hook_depth = %d\n", max_hook_depth);
11037     trace("max_hook_depth = %d\n", max_hook_depth);
11038 
11039     b = UnhookWindowsHookEx(recursive_hook);
11040     ok(b, "UnhokWindowsHookEx failed\n");
11041 
11042     DestroyWindow(hook_hwnd);
11043 }
11044 
11045 static const struct message ScrollWindowPaint1[] = {
11046     { WM_PAINT, sent },
11047     { WM_ERASEBKGND, sent|beginpaint },
11048     { WM_GETTEXTLENGTH, sent|optional },
11049     { WM_PAINT, sent|optional },
11050     { WM_NCPAINT, sent|beginpaint|optional },
11051     { WM_GETTEXT, sent|beginpaint|optional },
11052     { WM_GETTEXT, sent|beginpaint|optional },
11053     { WM_GETTEXT, sent|beginpaint|optional },
11054     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
11055     { WM_ERASEBKGND, sent|beginpaint|optional },
11056     { 0 }
11057 };
11058 
11059 static const struct message ScrollWindowPaint2[] = {
11060     { WM_PAINT, sent },
11061     { 0 }
11062 };
11063 
11064 static void test_scrollwindowex(void)
11065 {
11066     HWND hwnd, hchild;
11067     RECT rect={0,0,130,130};
11068 
11069     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
11070             WS_VISIBLE|WS_OVERLAPPEDWINDOW,
11071             100, 100, 200, 200, 0, 0, 0, NULL);
11072     ok (hwnd != 0, "Failed to create overlapped window\n");
11073     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
11074             WS_VISIBLE|WS_CAPTION|WS_CHILD,
11075             10, 10, 150, 150, hwnd, 0, 0, NULL);
11076     ok (hchild != 0, "Failed to create child\n");
11077     UpdateWindow(hwnd);
11078     flush_events();
11079     flush_sequence();
11080 
11081     /* scroll without the child window */
11082     trace("start scroll\n");
11083     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
11084             SW_ERASE|SW_INVALIDATE);
11085     ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE);
11086     trace("end scroll\n");
11087     flush_sequence();
11088     flush_events();
11089     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE);
11090     flush_events();
11091     flush_sequence();
11092 
11093     /* Now without the SW_ERASE flag */
11094     trace("start scroll\n");
11095     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
11096     ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE);
11097     trace("end scroll\n");
11098     flush_sequence();
11099     flush_events();
11100     ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", FALSE);
11101     flush_events();
11102     flush_sequence();
11103 
11104     /* now scroll the child window as well */
11105     trace("start scroll\n");
11106     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
11107             SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
11108     /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
11109     /* windows sometimes a WM_MOVE */
11110     ok_sequence(WmEmptySeq, "ScrollWindowEx", TRUE);
11111     trace("end scroll\n");
11112     flush_sequence();
11113     flush_events();
11114     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE);
11115     flush_events();
11116     flush_sequence();
11117 
11118     /* now scroll with ScrollWindow() */
11119     trace("start scroll with ScrollWindow\n");
11120     ScrollWindow( hwnd, 5, 5, NULL, NULL);
11121     trace("end scroll\n");
11122     flush_sequence();
11123     flush_events();
11124     ok_sequence(ScrollWindowPaint1, "ScrollWindow", FALSE);
11125 
11126     ok(DestroyWindow(hchild), "failed to destroy window\n");
11127     ok(DestroyWindow(hwnd), "failed to destroy window\n");
11128     flush_sequence();
11129 }
11130 
11131 static const struct message destroy_window_with_children[] = {
11132     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
11133     { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
11134     { 0x0090, sent|optional },
11135     { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
11136     { 0x0090, sent|optional },
11137     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
11138     { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
11139     { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
11140     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
11141     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
11142     { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
11143     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
11144     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
11145     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
11146     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
11147     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
11148     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
11149     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
11150     { 0 }
11151 };
11152 
11153 static void test_DestroyWindow(void)
11154 {
11155     BOOL ret;
11156     HWND parent, child1, child2, child3, child4, test;
11157     UINT_PTR child_id = WND_CHILD_ID + 1;
11158 
11159     parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
11160 			     100, 100, 200, 200, 0, 0, 0, NULL);
11161     assert(parent != 0);
11162     child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
11163 			     0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
11164     assert(child1 != 0);
11165     child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
11166 			     0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
11167     assert(child2 != 0);
11168     child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
11169 			     0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
11170     assert(child3 != 0);
11171     child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
11172 			     0, 0, 50, 50, parent, 0, 0, NULL);
11173     assert(child4 != 0);
11174 
11175     /* test owner/parent of child2 */
11176     test = GetParent(child2);
11177     ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
11178     ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
11179     if(pGetAncestor) {
11180         test = pGetAncestor(child2, GA_PARENT);
11181         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
11182     }
11183     test = GetWindow(child2, GW_OWNER);
11184     ok(!test, "wrong owner %p\n", test);
11185 
11186     test = SetParent(child2, parent);
11187     ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
11188 
11189     /* test owner/parent of the parent */
11190     test = GetParent(parent);
11191     ok(!test, "wrong parent %p\n", test);
11192     ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
11193     if(pGetAncestor) {
11194         test = pGetAncestor(parent, GA_PARENT);
11195         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
11196     }
11197     test = GetWindow(parent, GW_OWNER);
11198     ok(!test, "wrong owner %p\n", test);
11199 
11200     /* test owner/parent of child1 */
11201     test = GetParent(child1);
11202     ok(test == parent, "wrong parent %p\n", test);
11203     ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
11204     if(pGetAncestor) {
11205         test = pGetAncestor(child1, GA_PARENT);
11206         ok(test == parent, "wrong parent %p\n", test);
11207     }
11208     test = GetWindow(child1, GW_OWNER);
11209     ok(!test, "wrong owner %p\n", test);
11210 
11211     /* test owner/parent of child2 */
11212     test = GetParent(child2);
11213     ok(test == parent, "wrong parent %p\n", test);
11214     ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
11215     if(pGetAncestor) {
11216         test = pGetAncestor(child2, GA_PARENT);
11217         ok(test == parent, "wrong parent %p\n", test);
11218     }
11219     test = GetWindow(child2, GW_OWNER);
11220     ok(!test, "wrong owner %p\n", test);
11221 
11222     /* test owner/parent of child3 */
11223     test = GetParent(child3);
11224     ok(test == child1, "wrong parent %p\n", test);
11225     ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
11226     if(pGetAncestor) {
11227         test = pGetAncestor(child3, GA_PARENT);
11228         ok(test == child1, "wrong parent %p\n", test);
11229     }
11230     test = GetWindow(child3, GW_OWNER);
11231     ok(!test, "wrong owner %p\n", test);
11232 
11233     /* test owner/parent of child4 */
11234     test = GetParent(child4);
11235     ok(test == parent, "wrong parent %p\n", test);
11236     ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
11237     if(pGetAncestor) {
11238         test = pGetAncestor(child4, GA_PARENT);
11239         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
11240     }
11241     test = GetWindow(child4, GW_OWNER);
11242     ok(test == parent, "wrong owner %p\n", test);
11243 
11244     flush_sequence();
11245 
11246     trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
11247 	   parent, child1, child2, child3, child4);
11248 
11249     SetCapture(child4);
11250     test = GetCapture();
11251     ok(test == child4, "wrong capture window %p\n", test);
11252 
11253     test_DestroyWindow_flag = TRUE;
11254     ret = DestroyWindow(parent);
11255     ok( ret, "DestroyWindow() error %d\n", GetLastError());
11256     test_DestroyWindow_flag = FALSE;
11257     ok_sequence(destroy_window_with_children, "destroy window with children", FALSE);
11258 
11259     ok(!IsWindow(parent), "parent still exists\n");
11260     ok(!IsWindow(child1), "child1 still exists\n");
11261     ok(!IsWindow(child2), "child2 still exists\n");
11262     ok(!IsWindow(child3), "child3 still exists\n");
11263     ok(!IsWindow(child4), "child4 still exists\n");
11264 
11265     test = GetCapture();
11266     ok(!test, "wrong capture window %p\n", test);
11267 }
11268 
11269 
11270 static const struct message WmDispatchPaint[] = {
11271     { WM_NCPAINT, sent },
11272     { WM_GETTEXT, sent|defwinproc|optional },
11273     { WM_GETTEXT, sent|defwinproc|optional },
11274     { WM_ERASEBKGND, sent },
11275     { 0 }
11276 };
11277 
11278 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11279 {
11280     if (message == WM_PAINT) return 0;
11281     return MsgCheckProcA( hwnd, message, wParam, lParam );
11282 }
11283 
11284 static void test_DispatchMessage(void)
11285 {
11286     RECT rect;
11287     MSG msg;
11288     int count;
11289     HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
11290                                100, 100, 200, 200, 0, 0, 0, NULL);
11291     ShowWindow( hwnd, SW_SHOW );
11292     UpdateWindow( hwnd );
11293     flush_events();
11294     flush_sequence();
11295     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
11296 
11297     SetRect( &rect, -5, -5, 5, 5 );
11298     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
11299     count = 0;
11300     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
11301     {
11302         if (msg.message != WM_PAINT) DispatchMessageA( &msg );
11303         else
11304         {
11305             flush_sequence();
11306             DispatchMessageA( &msg );
11307             /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
11308             if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
11309             else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
11310             if (++count > 10) break;
11311         }
11312     }
11313     ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
11314 
11315     trace("now without DispatchMessage\n");
11316     flush_sequence();
11317     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
11318     count = 0;
11319     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
11320     {
11321         if (msg.message != WM_PAINT) DispatchMessageA( &msg );
11322         else
11323         {
11324             HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
11325             flush_sequence();
11326             /* this will send WM_NCCPAINT just like DispatchMessage does */
11327             GetUpdateRgn( hwnd, hrgn, TRUE );
11328             ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
11329             DeleteObject( hrgn );
11330             GetClientRect( hwnd, &rect );
11331             ValidateRect( hwnd, &rect );  /* this will stop WM_PAINTs */
11332             ok( !count, "Got multiple WM_PAINTs\n" );
11333             if (++count > 10) break;
11334         }
11335     }
11336 
11337     flush_sequence();
11338     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
11339     count = 0;
11340     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
11341     {
11342         if (msg.message != WM_PAINT) DispatchMessageA( &msg );
11343         else
11344         {
11345             HDC hdc;
11346 
11347             flush_sequence();
11348             hdc = BeginPaint( hwnd, NULL );
11349             ok( !hdc, "got valid hdc %p from BeginPaint\n", hdc );
11350             ok( !EndPaint( hwnd, NULL ), "EndPaint succeeded\n" );
11351             ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
11352             ok( !count, "Got multiple WM_PAINTs\n" );
11353             if (++count > 10) break;
11354         }
11355     }
11356     DestroyWindow(hwnd);
11357 }
11358 
11359 
11360 static const struct message WmUser[] = {
11361     { WM_USER, sent },
11362     { 0 }
11363 };
11364 
11365 struct sendmsg_info
11366 {
11367     HWND  hwnd;
11368     DWORD timeout;
11369     DWORD ret;
11370 };
11371 
11372 static DWORD CALLBACK send_msg_thread( LPVOID arg )
11373 {
11374     struct sendmsg_info *info = arg;
11375     SetLastError( 0xdeadbeef );
11376     info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
11377     if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT ||
11378                         broken(GetLastError() == 0),  /* win9x */
11379                         "unexpected error %d\n", GetLastError());
11380     return 0;
11381 }
11382 
11383 static void wait_for_thread( HANDLE thread )
11384 {
11385     while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
11386     {
11387         MSG msg;
11388         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA(&msg);
11389     }
11390 }
11391 
11392 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11393 {
11394     if (message == WM_USER) Sleep(200);
11395     return MsgCheckProcA( hwnd, message, wParam, lParam );
11396 }
11397 
11398 static void test_SendMessageTimeout(void)
11399 {
11400     HANDLE thread;
11401     struct sendmsg_info info;
11402     DWORD tid;
11403     BOOL is_win9x;
11404 
11405     info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
11406                                100, 100, 200, 200, 0, 0, 0, NULL);
11407     flush_events();
11408     flush_sequence();
11409 
11410     info.timeout = 1000;
11411     info.ret = 0xdeadbeef;
11412     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11413     wait_for_thread( thread );
11414     CloseHandle( thread );
11415     ok( info.ret == 1, "SendMessageTimeout failed\n" );
11416     ok_sequence( WmUser, "WmUser", FALSE );
11417 
11418     info.timeout = 1;
11419     info.ret = 0xdeadbeef;
11420     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11421     Sleep(100);  /* SendMessageTimeout should time out here */
11422     wait_for_thread( thread );
11423     CloseHandle( thread );
11424     ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
11425     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
11426 
11427     /* 0 means infinite timeout (but not on win9x) */
11428     info.timeout = 0;
11429     info.ret = 0xdeadbeef;
11430     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11431     Sleep(100);
11432     wait_for_thread( thread );
11433     CloseHandle( thread );
11434     is_win9x = !info.ret;
11435     if (is_win9x) ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
11436     else ok_sequence( WmUser, "WmUser", FALSE );
11437 
11438     /* timeout is treated as signed despite the prototype (but not on win9x) */
11439     info.timeout = 0x7fffffff;
11440     info.ret = 0xdeadbeef;
11441     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11442     Sleep(100);
11443     wait_for_thread( thread );
11444     CloseHandle( thread );
11445     ok( info.ret == 1, "SendMessageTimeout failed\n" );
11446     ok_sequence( WmUser, "WmUser", FALSE );
11447 
11448     info.timeout = 0x80000000;
11449     info.ret = 0xdeadbeef;
11450     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11451     Sleep(100);
11452     wait_for_thread( thread );
11453     CloseHandle( thread );
11454     if (is_win9x)
11455     {
11456         ok( info.ret == 1, "SendMessageTimeout failed\n" );
11457         ok_sequence( WmUser, "WmUser", FALSE );
11458     }
11459     else
11460     {
11461         ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
11462         ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
11463     }
11464 
11465     /* now check for timeout during message processing */
11466     SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
11467     info.timeout = 100;
11468     info.ret = 0xdeadbeef;
11469     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11470     wait_for_thread( thread );
11471     CloseHandle( thread );
11472     /* we should time out but still get the message */
11473     ok( info.ret == 0, "SendMessageTimeout failed\n" );
11474     ok_sequence( WmUser, "WmUser", FALSE );
11475 
11476     DestroyWindow( info.hwnd );
11477 }
11478 
11479 
11480 /****************** edit message test *************************/
11481 #define ID_EDIT 0x1234
11482 static const struct message sl_edit_setfocus[] =
11483 {
11484     { HCBT_SETFOCUS, hook },
11485     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11486     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11487     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11488     { WM_SETFOCUS, sent|wparam, 0 },
11489     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11490     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 },
11491     { WM_CTLCOLOREDIT, sent|parent },
11492     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11493     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11494     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11495     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11496     { 0 }
11497 };
11498 static const struct message sl_edit_invisible[] =
11499 {
11500     { HCBT_SETFOCUS, hook },
11501     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11502     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11503     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11504     { WM_KILLFOCUS, sent|parent },
11505     { WM_SETFOCUS, sent },
11506     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11507     { 0 }
11508 };
11509 static const struct message ml_edit_setfocus[] =
11510 {
11511     { HCBT_SETFOCUS, hook },
11512     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11513     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11514     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11515     { WM_SETFOCUS, sent|wparam, 0 },
11516     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11517     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11518     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11519     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11520     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11521     { 0 }
11522 };
11523 static const struct message sl_edit_killfocus[] =
11524 {
11525     { HCBT_SETFOCUS, hook },
11526     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11527     { WM_KILLFOCUS, sent|wparam, 0 },
11528     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11529     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11530     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
11531     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
11532     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
11533     { 0 }
11534 };
11535 static const struct message sl_edit_lbutton_dblclk[] =
11536 {
11537     { WM_LBUTTONDBLCLK, sent },
11538     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11539     { 0 }
11540 };
11541 static const struct message sl_edit_lbutton_down[] =
11542 {
11543     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
11544     { HCBT_SETFOCUS, hook },
11545     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11546     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11547     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11548     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
11549     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11550     { WM_CTLCOLOREDIT, sent|parent },
11551     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11552     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11553     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11554     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11555     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11556     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11557     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11558     { WM_CTLCOLOREDIT, sent|parent|optional },
11559     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11560     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11561     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11562     { 0 }
11563 };
11564 static const struct message ml_edit_lbutton_down[] =
11565 {
11566     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
11567     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11568     { HCBT_SETFOCUS, hook },
11569     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11570     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11571     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11572     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
11573     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11574     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11575     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11576     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11577     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11578     { 0 }
11579 };
11580 static const struct message sl_edit_lbutton_up[] =
11581 {
11582     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
11583     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11584     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
11585     { WM_CAPTURECHANGED, sent|defwinproc },
11586     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11587     { 0 }
11588 };
11589 static const struct message ml_edit_lbutton_up[] =
11590 {
11591     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
11592     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
11593     { WM_CAPTURECHANGED, sent|defwinproc },
11594     { 0 }
11595 };
11596 
11597 static WNDPROC old_edit_proc;
11598 
11599 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11600 {
11601     static LONG defwndproc_counter = 0;
11602     LRESULT ret;
11603     struct recvd_message msg;
11604 
11605     if (ignore_message( message )) return 0;
11606 
11607     msg.hwnd = hwnd;
11608     msg.message = message;
11609     msg.flags = sent|wparam|lparam;
11610     if (defwndproc_counter) msg.flags |= defwinproc;
11611     msg.wParam = wParam;
11612     msg.lParam = lParam;
11613     msg.descr = "edit";
11614     add_message(&msg);
11615 
11616     defwndproc_counter++;
11617     ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
11618     defwndproc_counter--;
11619 
11620     return ret;
11621 }
11622 
11623 static void subclass_edit(void)
11624 {
11625     WNDCLASSA cls;
11626 
11627     if (!GetClassInfoA(0, "edit", &cls)) assert(0);
11628 
11629     old_edit_proc = cls.lpfnWndProc;
11630 
11631     cls.hInstance = GetModuleHandleA(NULL);
11632     cls.lpfnWndProc = edit_hook_proc;
11633     cls.lpszClassName = "my_edit_class";
11634     UnregisterClassA(cls.lpszClassName, cls.hInstance);
11635     if (!RegisterClassA(&cls)) assert(0);
11636 }
11637 
11638 static void test_edit_messages(void)
11639 {
11640     HWND hwnd, parent;
11641     DWORD dlg_code;
11642 
11643     subclass_edit();
11644     log_all_parent_messages++;
11645 
11646     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11647                              100, 100, 200, 200, 0, 0, 0, NULL);
11648     ok (parent != 0, "Failed to create parent window\n");
11649 
11650     /* test single line edit */
11651     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
11652 			   0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
11653     ok(hwnd != 0, "Failed to create edit window\n");
11654 
11655     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
11656     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
11657 
11658     flush_sequence();
11659     SetFocus(hwnd);
11660     ok_sequence(sl_edit_invisible, "SetFocus(hwnd) on an invisible edit", FALSE);
11661 
11662     ShowWindow(hwnd, SW_SHOW);
11663     UpdateWindow(hwnd);
11664     SetFocus(0);
11665     flush_sequence();
11666 
11667     SetFocus(hwnd);
11668     ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
11669 
11670     SetFocus(0);
11671     ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
11672 
11673     SetFocus(0);
11674     ReleaseCapture();
11675     flush_sequence();
11676 
11677     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
11678     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
11679 
11680     SetFocus(0);
11681     ReleaseCapture();
11682     flush_sequence();
11683 
11684     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
11685     ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
11686 
11687     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
11688     ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
11689 
11690     DestroyWindow(hwnd);
11691 
11692     /* test multiline edit */
11693     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
11694 			   0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
11695     ok(hwnd != 0, "Failed to create edit window\n");
11696 
11697     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
11698     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
11699        "wrong dlg_code %08x\n", dlg_code);
11700 
11701     ShowWindow(hwnd, SW_SHOW);
11702     UpdateWindow(hwnd);
11703     SetFocus(0);
11704     flush_sequence();
11705 
11706     SetFocus(hwnd);
11707     ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
11708 
11709     SetFocus(0);
11710     ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
11711 
11712     SetFocus(0);
11713     ReleaseCapture();
11714     flush_sequence();
11715 
11716     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
11717     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
11718 
11719     SetFocus(0);
11720     ReleaseCapture();
11721     flush_sequence();
11722 
11723     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
11724     ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
11725 
11726     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
11727     ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
11728 
11729     DestroyWindow(hwnd);
11730     DestroyWindow(parent);
11731 
11732     log_all_parent_messages--;
11733 }
11734 
11735 /**************************** End of Edit test ******************************/
11736 
11737 static const struct message WmKeyDownSkippedSeq[] =
11738 {
11739     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
11740     { 0 }
11741 };
11742 static const struct message WmKeyDownWasDownSkippedSeq[] =
11743 {
11744     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x40000001 }, /* XP */
11745     { 0 }
11746 };
11747 static const struct message WmKeyUpSkippedSeq[] =
11748 {
11749     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
11750     { 0 }
11751 };
11752 static const struct message WmUserKeyUpSkippedSeq[] =
11753 {
11754     { WM_USER, sent },
11755     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
11756     { 0 }
11757 };
11758 
11759 #define EV_STOP 0
11760 #define EV_SENDMSG 1
11761 #define EV_ACK 2
11762 
11763 struct peekmsg_info
11764 {
11765     HWND  hwnd;
11766     HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
11767 };
11768 
11769 static DWORD CALLBACK send_msg_thread_2(void *param)
11770 {
11771     DWORD ret;
11772     struct peekmsg_info *info = param;
11773 
11774     trace("thread: looping\n");
11775     SetEvent(info->hevent[EV_ACK]);
11776 
11777     while (1)
11778     {
11779         ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
11780 
11781         switch (ret)
11782         {
11783         case WAIT_OBJECT_0 + EV_STOP:
11784             trace("thread: exiting\n");
11785             return 0;
11786 
11787         case WAIT_OBJECT_0 + EV_SENDMSG:
11788             trace("thread: sending message\n");
11789             ret = SendNotifyMessageA(info->hwnd, WM_USER, 0, 0);
11790             ok(ret, "SendNotifyMessageA failed error %u\n", GetLastError());
11791             SetEvent(info->hevent[EV_ACK]);
11792             break;
11793 
11794         default:
11795             trace("unexpected return: %04x\n", ret);
11796             assert(0);
11797             break;
11798         }
11799     }
11800     return 0;
11801 }
11802 
11803 static void test_PeekMessage(void)
11804 {
11805     MSG msg;
11806     HANDLE hthread;
11807     DWORD tid, qstatus;
11808     UINT qs_all_input = QS_ALLINPUT;
11809     UINT qs_input = QS_INPUT;
11810     BOOL ret;
11811     struct peekmsg_info info;
11812 
11813     info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
11814                               100, 100, 200, 200, 0, 0, 0, NULL);
11815     assert(info.hwnd);
11816     ShowWindow(info.hwnd, SW_SHOW);
11817     UpdateWindow(info.hwnd);
11818     SetFocus(info.hwnd);
11819 
11820     info.hevent[EV_STOP] = CreateEventA(NULL, 0, 0, NULL);
11821     info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
11822     info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
11823 
11824     hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
11825     WaitForSingleObject(info.hevent[EV_ACK], 10000);
11826 
11827     flush_events();
11828     flush_sequence();
11829 
11830     SetLastError(0xdeadbeef);
11831     qstatus = GetQueueStatus(qs_all_input);
11832     if (GetLastError() == ERROR_INVALID_FLAGS)
11833     {
11834         trace("QS_RAWINPUT not supported on this platform\n");
11835         qs_all_input &= ~QS_RAWINPUT;
11836         qs_input &= ~QS_RAWINPUT;
11837     }
11838     if (qstatus & QS_POSTMESSAGE)
11839     {
11840         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) /* nothing */ ;
11841         qstatus = GetQueueStatus(qs_all_input);
11842     }
11843     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
11844 
11845     trace("signalling to send message\n");
11846     SetEvent(info.hevent[EV_SENDMSG]);
11847     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11848 
11849     /* pass invalid QS_xxxx flags */
11850     SetLastError(0xdeadbeef);
11851     qstatus = GetQueueStatus(0xffffffff);
11852     ok(qstatus == 0 || broken(qstatus)  /* win9x */, "GetQueueStatus should fail: %08x\n", qstatus);
11853     if (!qstatus)
11854     {
11855         ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
11856         qstatus = GetQueueStatus(qs_all_input);
11857     }
11858     qstatus &= ~MAKELONG( 0x4000, 0x4000 );  /* sometimes set on Win95 */
11859     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
11860        "wrong qstatus %08x\n", qstatus);
11861 
11862     msg.message = 0;
11863     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11864     ok(!ret,
11865        "PeekMessageA should have returned FALSE instead of msg %04x\n",
11866         msg.message);
11867     ok_sequence(WmUser, "WmUser", FALSE);
11868 
11869     qstatus = GetQueueStatus(qs_all_input);
11870     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
11871 
11872     keybd_event('N', 0, 0, 0);
11873     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
11874     qstatus = GetQueueStatus(qs_all_input);
11875     if (!(qstatus & MAKELONG(QS_KEY, QS_KEY)))
11876     {
11877         skip( "queuing key events not supported\n" );
11878         goto done;
11879     }
11880     ok(qstatus == MAKELONG(QS_KEY, QS_KEY) ||
11881        /* keybd_event seems to trigger a sent message on NT4 */
11882        qstatus == MAKELONG(QS_KEY|QS_SENDMESSAGE, QS_KEY|QS_SENDMESSAGE),
11883        "wrong qstatus %08x\n", qstatus);
11884 
11885     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11886     qstatus = GetQueueStatus(qs_all_input);
11887     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY) ||
11888        qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
11889        "wrong qstatus %08x\n", qstatus);
11890 
11891     InvalidateRect(info.hwnd, NULL, FALSE);
11892     qstatus = GetQueueStatus(qs_all_input);
11893     ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY) ||
11894        qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
11895        "wrong qstatus %08x\n", qstatus);
11896 
11897     trace("signalling to send message\n");
11898     SetEvent(info.hevent[EV_SENDMSG]);
11899     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11900 
11901     qstatus = GetQueueStatus(qs_all_input);
11902     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11903        "wrong qstatus %08x\n", qstatus);
11904 
11905     msg.message = 0;
11906     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
11907     if (ret && msg.message == WM_CHAR)
11908     {
11909         win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
11910         goto done;
11911     }
11912     ok(!ret,
11913        "PeekMessageA should have returned FALSE instead of msg %04x\n",
11914         msg.message);
11915     if (!sequence_cnt)  /* nt4 doesn't fetch anything with PM_QS_* flags */
11916     {
11917         win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
11918         goto done;
11919     }
11920     ok_sequence(WmUser, "WmUser", FALSE);
11921 
11922     qstatus = GetQueueStatus(qs_all_input);
11923     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11924        "wrong qstatus %08x\n", qstatus);
11925 
11926     trace("signalling to send message\n");
11927     SetEvent(info.hevent[EV_SENDMSG]);
11928     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11929 
11930     qstatus = GetQueueStatus(qs_all_input);
11931     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11932        "wrong qstatus %08x\n", qstatus);
11933 
11934     msg.message = 0;
11935     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE );
11936     ok(!ret,
11937        "PeekMessageA should have returned FALSE instead of msg %04x\n",
11938         msg.message);
11939     ok_sequence(WmUser, "WmUser", FALSE);
11940 
11941     qstatus = GetQueueStatus(qs_all_input);
11942     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11943        "wrong qstatus %08x\n", qstatus);
11944 
11945     msg.message = 0;
11946     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
11947     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11948        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11949        ret, msg.message, msg.wParam);
11950     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11951 
11952     qstatus = GetQueueStatus(qs_all_input);
11953     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
11954        "wrong qstatus %08x\n", qstatus);
11955 
11956     msg.message = 0;
11957     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
11958     ok(!ret,
11959        "PeekMessageA should have returned FALSE instead of msg %04x\n",
11960         msg.message);
11961     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11962 
11963     qstatus = GetQueueStatus(qs_all_input);
11964     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
11965        "wrong qstatus %08x\n", qstatus);
11966 
11967     msg.message = 0;
11968     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
11969     ok(ret && msg.message == WM_PAINT,
11970        "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
11971     DispatchMessageA(&msg);
11972     ok_sequence(WmPaint, "WmPaint", FALSE);
11973 
11974     qstatus = GetQueueStatus(qs_all_input);
11975     ok(qstatus == MAKELONG(0, QS_KEY),
11976        "wrong qstatus %08x\n", qstatus);
11977 
11978     msg.message = 0;
11979     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
11980     ok(!ret,
11981        "PeekMessageA should have returned FALSE instead of msg %04x\n",
11982         msg.message);
11983     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11984 
11985     qstatus = GetQueueStatus(qs_all_input);
11986     ok(qstatus == MAKELONG(0, QS_KEY),
11987        "wrong qstatus %08x\n", qstatus);
11988 
11989     trace("signalling to send message\n");
11990     SetEvent(info.hevent[EV_SENDMSG]);
11991     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11992 
11993     qstatus = GetQueueStatus(qs_all_input);
11994     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
11995        "wrong qstatus %08x\n", qstatus);
11996 
11997     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11998 
11999     qstatus = GetQueueStatus(qs_all_input);
12000     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
12001        "wrong qstatus %08x\n", qstatus);
12002 
12003     msg.message = 0;
12004     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
12005     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
12006        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
12007        ret, msg.message, msg.wParam);
12008     ok_sequence(WmUser, "WmUser", FALSE);
12009 
12010     qstatus = GetQueueStatus(qs_all_input);
12011     ok(qstatus == MAKELONG(0, QS_KEY),
12012        "wrong qstatus %08x\n", qstatus);
12013 
12014     msg.message = 0;
12015     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
12016     ok(!ret,
12017        "PeekMessageA should have returned FALSE instead of msg %04x\n",
12018         msg.message);
12019     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12020 
12021     qstatus = GetQueueStatus(qs_all_input);
12022     ok(qstatus == MAKELONG(0, QS_KEY),
12023        "wrong qstatus %08x\n", qstatus);
12024 
12025     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
12026 
12027     qstatus = GetQueueStatus(qs_all_input);
12028     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
12029        "wrong qstatus %08x\n", qstatus);
12030 
12031     trace("signalling to send message\n");
12032     SetEvent(info.hevent[EV_SENDMSG]);
12033     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
12034 
12035     qstatus = GetQueueStatus(qs_all_input);
12036     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
12037        "wrong qstatus %08x\n", qstatus);
12038 
12039     msg.message = 0;
12040     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
12041     ok(!ret,
12042        "PeekMessageA should have returned FALSE instead of msg %04x\n",
12043         msg.message);
12044     ok_sequence(WmUser, "WmUser", FALSE);
12045 
12046     qstatus = GetQueueStatus(qs_all_input);
12047     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
12048        "wrong qstatus %08x\n", qstatus);
12049 
12050     msg.message = 0;
12051     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
12052         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
12053     else /* workaround for a missing QS_RAWINPUT support */
12054         ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
12055     ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
12056        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
12057        ret, msg.message, msg.wParam);
12058     ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
12059 
12060     qstatus = GetQueueStatus(qs_all_input);
12061     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
12062        "wrong qstatus %08x\n", qstatus);
12063 
12064     msg.message = 0;
12065     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
12066         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
12067     else /* workaround for a missing QS_RAWINPUT support */
12068         ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
12069     ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
12070        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYUP wParam 'N'\n",
12071        ret, msg.message, msg.wParam);
12072     ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
12073 
12074     qstatus = GetQueueStatus(qs_all_input);
12075     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
12076        "wrong qstatus %08x\n", qstatus);
12077 
12078     msg.message = 0;
12079     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
12080     ok(!ret,
12081        "PeekMessageA should have returned FALSE instead of msg %04x\n",
12082         msg.message);
12083     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12084 
12085     qstatus = GetQueueStatus(qs_all_input);
12086     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
12087        "wrong qstatus %08x\n", qstatus);
12088 
12089     msg.message = 0;
12090     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
12091     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
12092        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
12093        ret, msg.message, msg.wParam);
12094     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12095 
12096     qstatus = GetQueueStatus(qs_all_input);
12097     ok(qstatus == 0,
12098        "wrong qstatus %08x\n", qstatus);
12099 
12100     msg.message = 0;
12101     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
12102     ok(!ret,
12103        "PeekMessageA should have returned FALSE instead of msg %04x\n",
12104         msg.message);
12105     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12106 
12107     qstatus = GetQueueStatus(qs_all_input);
12108     ok(qstatus == 0,
12109        "wrong qstatus %08x\n", qstatus);
12110 
12111     /* test whether presence of the quit flag in the queue affects
12112      * the queue state
12113      */
12114     PostQuitMessage(0x1234abcd);
12115 
12116     qstatus = GetQueueStatus(qs_all_input);
12117     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
12118        "wrong qstatus %08x\n", qstatus);
12119 
12120     PostMessageA(info.hwnd, WM_USER, 0, 0);
12121 
12122     qstatus = GetQueueStatus(qs_all_input);
12123     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
12124        "wrong qstatus %08x\n", qstatus);
12125 
12126     msg.message = 0;
12127     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
12128     ok(ret && msg.message == WM_USER,
12129        "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
12130     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12131 
12132     qstatus = GetQueueStatus(qs_all_input);
12133     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
12134        "wrong qstatus %08x\n", qstatus);
12135 
12136     msg.message = 0;
12137     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
12138     ok(ret && msg.message == WM_QUIT,
12139        "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
12140     ok(msg.wParam == 0x1234abcd, "got wParam %08lx instead of 0x1234abcd\n", msg.wParam);
12141     ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
12142     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12143 
12144     qstatus = GetQueueStatus(qs_all_input);
12145 todo_wine {
12146     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
12147        "wrong qstatus %08x\n", qstatus);
12148 }
12149 
12150     msg.message = 0;
12151     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
12152     ok(!ret,
12153        "PeekMessageA should have returned FALSE instead of msg %04x\n",
12154         msg.message);
12155     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12156 
12157     qstatus = GetQueueStatus(qs_all_input);
12158     ok(qstatus == 0,
12159        "wrong qstatus %08x\n", qstatus);
12160 
12161     /* some GetMessage tests */
12162 
12163     keybd_event('N', 0, 0, 0);
12164     qstatus = GetQueueStatus(qs_all_input);
12165     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
12166 
12167     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
12168     qstatus = GetQueueStatus(qs_all_input);
12169     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
12170 
12171     if (qstatus)
12172     {
12173         ret = GetMessageA( &msg, 0, 0, 0 );
12174         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
12175            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
12176            ret, msg.message, msg.wParam);
12177         qstatus = GetQueueStatus(qs_all_input);
12178         ok(qstatus == MAKELONG(0, QS_KEY), "wrong qstatus %08x\n", qstatus);
12179     }
12180 
12181     if (qstatus)
12182     {
12183         ret = GetMessageA( &msg, 0, 0, 0 );
12184         ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
12185            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
12186            ret, msg.message, msg.wParam);
12187         ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
12188         qstatus = GetQueueStatus(qs_all_input);
12189         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
12190     }
12191 
12192     keybd_event('N', 0, 0, 0);
12193     qstatus = GetQueueStatus(qs_all_input);
12194     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
12195 
12196     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
12197     qstatus = GetQueueStatus(qs_all_input);
12198     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
12199 
12200     if (qstatus & (QS_KEY << 16))
12201     {
12202         ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
12203         ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
12204            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
12205            ret, msg.message, msg.wParam);
12206         ok_sequence(WmKeyDownWasDownSkippedSeq, "WmKeyDownWasDownSkippedSeq", FALSE);
12207         qstatus = GetQueueStatus(qs_all_input);
12208         ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
12209     }
12210 
12211     if (qstatus)
12212     {
12213         ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
12214         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
12215            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
12216            ret, msg.message, msg.wParam);
12217         qstatus = GetQueueStatus(qs_all_input);
12218         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
12219     }
12220 
12221     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
12222     qstatus = GetQueueStatus(qs_all_input);
12223     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
12224 
12225     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
12226     qstatus = GetQueueStatus(qs_all_input);
12227     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
12228 
12229     trace("signalling to send message\n");
12230     SetEvent(info.hevent[EV_SENDMSG]);
12231     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
12232     qstatus = GetQueueStatus(qs_all_input);
12233     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
12234        "wrong qstatus %08x\n", qstatus);
12235 
12236     if (qstatus & (QS_KEY << 16))
12237     {
12238         ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
12239         ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
12240            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
12241            ret, msg.message, msg.wParam);
12242         ok_sequence(WmUserKeyUpSkippedSeq, "WmUserKeyUpSkippedSeq", FALSE);
12243         qstatus = GetQueueStatus(qs_all_input);
12244         ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
12245     }
12246 
12247     if (qstatus)
12248     {
12249         ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
12250         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
12251            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
12252            ret, msg.message, msg.wParam);
12253         qstatus = GetQueueStatus(qs_all_input);
12254         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
12255     }
12256 
12257     PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
12258     ret = PeekMessageA(&msg, (HWND)-1, 0, 0, PM_NOREMOVE);
12259     ok(ret == TRUE, "wrong ret %d\n", ret);
12260     ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
12261     ret = GetMessageA(&msg, (HWND)-1, 0, 0);
12262     ok(ret == TRUE, "wrong ret %d\n", ret);
12263     ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
12264 
12265     PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
12266     ret = PeekMessageA(&msg, (HWND)1, 0, 0, PM_NOREMOVE);
12267     ok(ret == TRUE, "wrong ret %d\n", ret);
12268     ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
12269     ret = GetMessageA(&msg, (HWND)1, 0, 0);
12270     ok(ret == TRUE, "wrong ret %d\n", ret);
12271     ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
12272 
12273     PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
12274     ret = PeekMessageA(&msg, (HWND)0xffff, 0, 0, PM_NOREMOVE);
12275     ok(ret == TRUE, "wrong ret %d\n", ret);
12276     ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
12277     ret = GetMessageA(&msg, (HWND)0xffff, 0, 0);
12278     ok(ret == TRUE, "wrong ret %d\n", ret);
12279     ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
12280 
12281 done:
12282     trace("signalling to exit\n");
12283     SetEvent(info.hevent[EV_STOP]);
12284 
12285     WaitForSingleObject(hthread, INFINITE);
12286 
12287     CloseHandle(hthread);
12288     CloseHandle(info.hevent[0]);
12289     CloseHandle(info.hevent[1]);
12290     CloseHandle(info.hevent[2]);
12291 
12292     DestroyWindow(info.hwnd);
12293 }
12294 
12295 static void wait_move_event(HWND hwnd, int x, int y)
12296 {
12297     MSG msg;
12298     DWORD time;
12299     BOOL ret;
12300 
12301     time = GetTickCount();
12302     while (GetTickCount() - time < 200) {
12303 	ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
12304         if (ret && msg.pt.x > x && msg.pt.y > y) break;
12305         if (!ret) MsgWaitForMultipleObjects( 0, NULL, FALSE, GetTickCount() - time, QS_ALLINPUT );
12306         else Sleep( GetTickCount() - time );
12307     }
12308 }
12309 
12310 #define STEP 5
12311 static void test_PeekMessage2(void)
12312 {
12313     HWND hwnd;
12314     BOOL ret;
12315     MSG msg;
12316     UINT message;
12317     DWORD time1, time2, time3;
12318     int x1, y1, x2, y2, x3, y3;
12319     POINT pos;
12320 
12321     time1 = time2 = time3 = 0;
12322     x1 = y1 = x2 = y2 = x3 = y3 = 0;
12323 
12324     /* Initialise window and make sure it is ready for events */
12325     hwnd = CreateWindowA("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
12326                         10, 10, 800, 800, NULL, NULL, NULL, NULL);
12327     assert(hwnd);
12328     trace("Window for test_PeekMessage2 %p\n", hwnd);
12329     ShowWindow(hwnd, SW_SHOW);
12330     UpdateWindow(hwnd);
12331     SetFocus(hwnd);
12332     GetCursorPos(&pos);
12333     SetCursorPos(100, 100);
12334     mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
12335     flush_events();
12336 
12337     /* Do initial mousemove, wait until we can see it
12338        and then do our test peek with PM_NOREMOVE. */
12339     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
12340     wait_move_event(hwnd, 100-STEP, 100-STEP);
12341 
12342     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
12343     if (!ret)
12344     {
12345         skip( "queuing mouse events not supported\n" );
12346         goto done;
12347     }
12348     else
12349     {
12350 	trace("1st move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
12351 	message = msg.message;
12352 	time1 = msg.time;
12353 	x1 = msg.pt.x;
12354 	y1 = msg.pt.y;
12355         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
12356     }
12357 
12358     /* Allow time to advance a bit, and then simulate the user moving their
12359      * mouse around. After that we peek again with PM_NOREMOVE.
12360      * Although the previous mousemove message was never removed, the
12361      * mousemove we now peek should reflect the recent mouse movements
12362      * because the input queue will merge the move events. */
12363     Sleep(100);
12364     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
12365     wait_move_event(hwnd, x1, y1);
12366 
12367     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
12368     ok(ret, "no message available\n");
12369     if (ret) {
12370 	trace("2nd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
12371 	message = msg.message;
12372 	time2 = msg.time;
12373 	x2 = msg.pt.x;
12374 	y2 = msg.pt.y;
12375         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
12376 	ok(time2 > time1, "message time not advanced: %x %x\n", time1, time2);
12377 	ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
12378     }
12379 
12380     /* Have another go, to drive the point home */
12381     Sleep(100);
12382     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
12383     wait_move_event(hwnd, x2, y2);
12384 
12385     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
12386     ok(ret, "no message available\n");
12387     if (ret) {
12388 	trace("3rd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
12389 	message = msg.message;
12390 	time3 = msg.time;
12391 	x3 = msg.pt.x;
12392 	y3 = msg.pt.y;
12393         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
12394 	ok(time3 > time2, "message time not advanced: %x %x\n", time2, time3);
12395 	ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
12396     }
12397 
12398 done:
12399     DestroyWindow(hwnd);
12400     SetCursorPos(pos.x, pos.y);
12401     flush_events();
12402 }
12403 
12404 static void test_PeekMessage3(void)
12405 {
12406     HWND hwnd;
12407     BOOL ret;
12408     MSG msg;
12409 
12410     hwnd = CreateWindowA("TestWindowClass", "PeekMessage3", WS_OVERLAPPEDWINDOW,
12411                          10, 10, 800, 800, NULL, NULL, NULL, NULL);
12412     ok(hwnd != NULL, "expected hwnd != NULL\n");
12413     flush_events();
12414 
12415     /* GetMessage() and PeekMessage(..., PM_REMOVE) should prefer messages which
12416      * were already seen. */
12417 
12418     SetTimer(hwnd, 1, 0, NULL);
12419     while (!PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE));
12420     ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12421     PostMessageA(hwnd, WM_USER, 0, 0);
12422     ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
12423     ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12424     ret = GetMessageA(&msg, NULL, 0, 0);
12425     ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12426     ret = GetMessageA(&msg, NULL, 0, 0);
12427     ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12428     ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12429     ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12430 
12431     SetTimer(hwnd, 1, 0, NULL);
12432     while (!PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE));
12433     ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12434     PostMessageA(hwnd, WM_USER, 0, 0);
12435     ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12436     ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12437     ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12438     ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12439     ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12440     ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12441 
12442     /* It doesn't matter if a message range is specified or not. */
12443 
12444     SetTimer(hwnd, 1, 0, NULL);
12445     while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12446     ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12447     PostMessageA(hwnd, WM_USER, 0, 0);
12448     ret = GetMessageA(&msg, NULL, 0, 0);
12449     ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12450     ret = GetMessageA(&msg, NULL, 0, 0);
12451     ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12452     ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12453     ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12454 
12455     /* But not if the post messages were added before the PeekMessage() call. */
12456 
12457     PostMessageA(hwnd, WM_USER, 0, 0);
12458     SetTimer(hwnd, 1, 0, NULL);
12459     while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12460     ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12461     ret = GetMessageA(&msg, NULL, 0, 0);
12462     ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12463     ret = GetMessageA(&msg, NULL, 0, 0);
12464     ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12465     ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12466     ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12467 
12468     /* More complicated test with multiple messages. */
12469 
12470     PostMessageA(hwnd, WM_USER, 0, 0);
12471     SetTimer(hwnd, 1, 0, NULL);
12472     while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12473     ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12474     PostMessageA(hwnd, WM_USER + 1, 0, 0);
12475     ret = GetMessageA(&msg, NULL, 0, 0);
12476     ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12477     ret = GetMessageA(&msg, NULL, 0, 0);
12478     ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12479     ret = GetMessageA(&msg, NULL, 0, 0);
12480     ok(ret && msg.message == WM_USER + 1, "msg.message = %u instead of WM_USER + 1\n", msg.message);
12481     ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12482     ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12483 
12484     /* Newer messages are still returned when specifying a message range. */
12485 
12486     SetTimer(hwnd, 1, 0, NULL);
12487     while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12488     ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12489     PostMessageA(hwnd, WM_USER + 1, 0, 0);
12490     PostMessageA(hwnd, WM_USER, 0, 0);
12491     ret = PeekMessageA(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
12492     ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12493     ret = PeekMessageA(&msg, NULL, WM_USER, WM_USER + 1, PM_NOREMOVE);
12494     ok(ret && msg.message == WM_USER + 1, "msg.message = %u instead of WM_USER + 1\n", msg.message);
12495     ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12496     ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12497     ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12498     ok(ret && msg.message == WM_USER + 1, "msg.message = %u instead of WM_USER + 1\n", msg.message);
12499     ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12500     ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12501     ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12502     ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12503 
12504     /* Also works for posted messages, but the situation is a bit different,
12505      * because both messages are in the same queue. */
12506 
12507     PostMessageA(hwnd, WM_TIMER, 0, 0);
12508     while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12509     ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12510     PostMessageA(hwnd, WM_USER, 0, 0);
12511     ret = GetMessageA(&msg, NULL, 0, 0);
12512     ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12513     ret = GetMessageA(&msg, NULL, 0, 0);
12514     ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12515     ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12516     ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12517 
12518     PostMessageA(hwnd, WM_USER, 0, 0);
12519     PostMessageA(hwnd, WM_TIMER, 0, 0);
12520     while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12521     ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12522     ret = GetMessageA(&msg, NULL, 0, 0);
12523     ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12524     ret = GetMessageA(&msg, NULL, 0, 0);
12525     ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12526     ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12527     ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12528 
12529     DestroyWindow(hwnd);
12530     flush_events();
12531 }
12532 
12533 static INT_PTR CALLBACK wm_quit_dlg_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
12534 {
12535     struct recvd_message msg;
12536 
12537     if (ignore_message( message )) return 0;
12538 
12539     msg.hwnd = hwnd;
12540     msg.message = message;
12541     msg.flags = sent|wparam|lparam;
12542     msg.wParam = wp;
12543     msg.lParam = lp;
12544     msg.descr = "dialog";
12545     add_message(&msg);
12546 
12547     switch (message)
12548     {
12549     case WM_INITDIALOG:
12550         PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
12551         PostMessageA(hwnd, WM_USER, 0xdead, 0xbeef);
12552         return 0;
12553 
12554     case WM_GETDLGCODE:
12555         return 0;
12556 
12557     case WM_USER:
12558         EndDialog(hwnd, 0);
12559         break;
12560     }
12561 
12562     return 1;
12563 }
12564 
12565 static const struct message WmQuitDialogSeq[] = {
12566     { HCBT_CREATEWND, hook },
12567     { WM_SETFONT, sent },
12568     { WM_INITDIALOG, sent },
12569     { WM_CHANGEUISTATE, sent|optional },
12570     { HCBT_DESTROYWND, hook },
12571     { 0x0090, sent|optional }, /* Vista */
12572     { WM_DESTROY, sent },
12573     { WM_NCDESTROY, sent },
12574     { 0 }
12575 };
12576 
12577 static const struct message WmStopQuitSeq[] = {
12578     { WM_DWMNCRENDERINGCHANGED, posted|optional },
12579     { WM_CLOSE, posted },
12580     { WM_QUIT, posted|wparam|lparam, 0x1234, 0 },
12581     { 0 }
12582 };
12583 
12584 static void test_quit_message(void)
12585 {
12586     MSG msg;
12587     BOOL ret;
12588 
12589     /* test using PostQuitMessage */
12590     flush_events();
12591     PostQuitMessage(0xbeef);
12592 
12593     msg.message = 0;
12594     ret = PeekMessageA(&msg, 0, 0, 0, PM_QS_SENDMESSAGE);
12595     ok(!ret, "got %x message\n", msg.message);
12596 
12597     ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
12598     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
12599     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12600     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
12601 
12602     ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
12603     ok(ret, "PostMessage failed with error %d\n", GetLastError());
12604 
12605     ret = GetMessageA(&msg, NULL, 0, 0);
12606     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
12607     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
12608 
12609     /* note: WM_QUIT message received after WM_USER message */
12610     ret = GetMessageA(&msg, NULL, 0, 0);
12611     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
12612     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12613     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
12614 
12615     ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12616     ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
12617 
12618     /* now test with PostThreadMessage - different behaviour! */
12619     PostThreadMessageA(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
12620 
12621     ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
12622     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
12623     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12624     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
12625 
12626     ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
12627     ok(ret, "PostMessage failed with error %d\n", GetLastError());
12628 
12629     /* note: we receive the WM_QUIT message first this time */
12630     ret = GetMessageA(&msg, NULL, 0, 0);
12631     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
12632     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12633     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
12634 
12635     ret = GetMessageA(&msg, NULL, 0, 0);
12636     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
12637     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
12638 
12639     flush_events();
12640     flush_sequence();
12641     ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, wm_quit_dlg_proc, 0);
12642     ok(ret == 1, "expected 1, got %d\n", ret);
12643     ok_sequence(WmQuitDialogSeq, "WmQuitDialogSeq", FALSE);
12644     memset(&msg, 0xab, sizeof(msg));
12645     ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12646     ok(ret, "PeekMessage failed\n");
12647     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12648     ok(msg.wParam == 0x1234, "wParam was 0x%lx instead of 0x1234\n", msg.wParam);
12649     ok(msg.lParam == 0, "lParam was 0x%lx instead of 0\n", msg.lParam);
12650 
12651     /* Check what happens to a WM_QUIT message posted to a window that gets
12652      * destroyed.
12653      */
12654     CreateWindowExA(0, "StopQuitClass", "Stop Quit Test", WS_OVERLAPPEDWINDOW,
12655                     0, 0, 100, 100, NULL, NULL, NULL, NULL);
12656     flush_sequence();
12657     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12658     {
12659         struct recvd_message rmsg;
12660         rmsg.hwnd = msg.hwnd;
12661         rmsg.message = msg.message;
12662         rmsg.flags = posted|wparam|lparam;
12663         rmsg.wParam = msg.wParam;
12664         rmsg.lParam = msg.lParam;
12665         rmsg.descr = "stop/quit";
12666         if (msg.message == WM_QUIT)
12667             /* The hwnd can only be checked here */
12668             ok(!msg.hwnd, "The WM_QUIT hwnd was %p instead of NULL\n", msg.hwnd);
12669         add_message(&rmsg);
12670         DispatchMessageA(&msg);
12671     }
12672     ok_sequence(WmStopQuitSeq, "WmStopQuitSeq", FALSE);
12673 }
12674 
12675 static const struct message WmNotifySeq[] = {
12676     { WM_NOTIFY, sent|wparam|lparam, 0x1234, 0xdeadbeef },
12677     { 0 }
12678 };
12679 
12680 static void test_notify_message(void)
12681 {
12682     HWND hwnd;
12683     BOOL ret;
12684     MSG msg;
12685 
12686     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
12687                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0, NULL, NULL, 0);
12688     ok(hwnd != 0, "Failed to create window\n");
12689     flush_events();
12690     flush_sequence();
12691 
12692     ret = SendNotifyMessageA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12693     ok(ret == TRUE, "SendNotifyMessageA failed with error %u\n", GetLastError());
12694     ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12695 
12696     ret = SendNotifyMessageW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12697     ok(ret == TRUE, "SendNotifyMessageW failed with error %u\n", GetLastError());
12698     ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12699 
12700     ret = SendMessageCallbackA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef, NULL, 0);
12701     ok(ret == TRUE, "SendMessageCallbackA failed with error %u\n", GetLastError());
12702     ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12703 
12704     ret = SendMessageCallbackW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef, NULL, 0);
12705     ok(ret == TRUE, "SendMessageCallbackW failed with error %u\n", GetLastError());
12706     ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12707 
12708     ret = PostMessageA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12709     ok(ret == TRUE, "PostMessageA failed with error %u\n", GetLastError());
12710     flush_events();
12711     ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12712 
12713     ret = PostMessageW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12714     ok(ret == TRUE, "PostMessageW failed with error %u\n", GetLastError());
12715     flush_events();
12716     ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12717 
12718     ret = PostThreadMessageA(GetCurrentThreadId(), WM_NOTIFY, 0x1234, 0xdeadbeef);
12719     ok(ret == TRUE, "PostThreadMessageA failed with error %u\n", GetLastError());
12720     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12721     {
12722         msg.hwnd = hwnd;
12723         DispatchMessageA(&msg);
12724     }
12725     ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12726 
12727     ret = PostThreadMessageW(GetCurrentThreadId(), WM_NOTIFY, 0x1234, 0xdeadbeef);
12728     ok(ret == TRUE, "PostThreadMessageW failed with error %u\n", GetLastError());
12729     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12730     {
12731         msg.hwnd = hwnd;
12732         DispatchMessageA(&msg);
12733     }
12734     ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12735 
12736     DestroyWindow(hwnd);
12737 }
12738 
12739 static const struct message WmMouseHoverSeq[] = {
12740     { WM_MOUSEACTIVATE, sent|optional },  /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
12741     { WM_MOUSEACTIVATE, sent|optional },
12742     { WM_TIMER, sent|optional }, /* XP sends it */
12743     { WM_SYSTIMER, sent },
12744     { WM_MOUSEHOVER, sent|wparam, 0 },
12745     { 0 }
12746 };
12747 
12748 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
12749 {
12750     MSG msg;
12751     DWORD start_ticks, end_ticks;
12752 
12753     start_ticks = GetTickCount();
12754     /* add some deviation (50%) to cover not expected delays */
12755     start_ticks += timeout / 2;
12756 
12757     do
12758     {
12759         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12760         {
12761             /* Timer proc messages are not dispatched to the window proc,
12762              * and therefore not logged.
12763              */
12764             if ((msg.message == WM_TIMER || msg.message == WM_SYSTIMER) && msg.hwnd)
12765             {
12766                 struct recvd_message s_msg;
12767 
12768                 s_msg.hwnd = msg.hwnd;
12769                 s_msg.message = msg.message;
12770                 s_msg.flags = sent|wparam|lparam;
12771                 s_msg.wParam = msg.wParam;
12772                 s_msg.lParam = msg.lParam;
12773                 s_msg.descr = "msg_loop";
12774                 add_message(&s_msg);
12775             }
12776             DispatchMessageA(&msg);
12777         }
12778 
12779         end_ticks = GetTickCount();
12780 
12781         /* inject WM_MOUSEMOVE to see how it changes tracking */
12782         if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
12783         {
12784             mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
12785             mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
12786 
12787             inject_mouse_move = FALSE;
12788         }
12789     } while (start_ticks + timeout >= end_ticks);
12790 }
12791 
12792 static void test_TrackMouseEvent(void)
12793 {
12794     TRACKMOUSEEVENT tme;
12795     BOOL ret;
12796     HWND hwnd, hchild;
12797     RECT rc_parent, rc_child;
12798     UINT default_hover_time, hover_width = 0, hover_height = 0;
12799 
12800 #define track_hover(track_hwnd, track_hover_time) \
12801     tme.cbSize = sizeof(tme); \
12802     tme.dwFlags = TME_HOVER; \
12803     tme.hwndTrack = track_hwnd; \
12804     tme.dwHoverTime = track_hover_time; \
12805     SetLastError(0xdeadbeef); \
12806     ret = pTrackMouseEvent(&tme); \
12807     ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
12808 
12809 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
12810     tme.cbSize = sizeof(tme); \
12811     tme.dwFlags = TME_QUERY; \
12812     tme.hwndTrack = (HWND)0xdeadbeef; \
12813     tme.dwHoverTime = 0xdeadbeef; \
12814     SetLastError(0xdeadbeef); \
12815     ret = pTrackMouseEvent(&tme); \
12816     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
12817     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
12818     ok(tme.dwFlags == (expected_track_flags), \
12819        "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
12820     ok(tme.hwndTrack == (expected_track_hwnd), \
12821        "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
12822     ok(tme.dwHoverTime == (expected_hover_time), \
12823        "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
12824 
12825 #define track_hover_cancel(track_hwnd) \
12826     tme.cbSize = sizeof(tme); \
12827     tme.dwFlags = TME_HOVER | TME_CANCEL; \
12828     tme.hwndTrack = track_hwnd; \
12829     tme.dwHoverTime = 0xdeadbeef; \
12830     SetLastError(0xdeadbeef); \
12831     ret = pTrackMouseEvent(&tme); \
12832     ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
12833 
12834     default_hover_time = 0xdeadbeef;
12835     SetLastError(0xdeadbeef);
12836     ret = SystemParametersInfoA(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
12837     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
12838        "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
12839     if (!ret) default_hover_time = 400;
12840     trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
12841 
12842     SetLastError(0xdeadbeef);
12843     ret = SystemParametersInfoA(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
12844     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
12845        "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
12846     if (!ret) hover_width = 4;
12847     SetLastError(0xdeadbeef);
12848     ret = SystemParametersInfoA(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
12849     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
12850        "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
12851     if (!ret) hover_height = 4;
12852     trace("hover rect is %u x %d\n", hover_width, hover_height);
12853 
12854     hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
12855 			  WS_OVERLAPPEDWINDOW | WS_VISIBLE,
12856 			  CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
12857 			  NULL, NULL, 0);
12858     assert(hwnd);
12859 
12860     hchild = CreateWindowExA(0, "TestWindowClass", NULL,
12861 			  WS_CHILD | WS_BORDER | WS_VISIBLE,
12862 			  50, 50, 200, 200, hwnd,
12863 			  NULL, NULL, 0);
12864     assert(hchild);
12865 
12866     SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
12867     flush_events();
12868     flush_sequence();
12869 
12870     tme.cbSize = 0;
12871     tme.dwFlags = TME_QUERY;
12872     tme.hwndTrack = (HWND)0xdeadbeef;
12873     tme.dwHoverTime = 0xdeadbeef;
12874     SetLastError(0xdeadbeef);
12875     ret = pTrackMouseEvent(&tme);
12876     ok(!ret, "TrackMouseEvent should fail\n");
12877     ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef),
12878        "not expected error %u\n", GetLastError());
12879 
12880     tme.cbSize = sizeof(tme);
12881     tme.dwFlags = TME_HOVER;
12882     tme.hwndTrack = (HWND)0xdeadbeef;
12883     tme.dwHoverTime = 0xdeadbeef;
12884     SetLastError(0xdeadbeef);
12885     ret = pTrackMouseEvent(&tme);
12886     ok(!ret, "TrackMouseEvent should fail\n");
12887     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
12888        "not expected error %u\n", GetLastError());
12889 
12890     tme.cbSize = sizeof(tme);
12891     tme.dwFlags = TME_HOVER | TME_CANCEL;
12892     tme.hwndTrack = (HWND)0xdeadbeef;
12893     tme.dwHoverTime = 0xdeadbeef;
12894     SetLastError(0xdeadbeef);
12895     ret = pTrackMouseEvent(&tme);
12896     ok(!ret, "TrackMouseEvent should fail\n");
12897     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
12898        "not expected error %u\n", GetLastError());
12899 
12900     GetWindowRect(hwnd, &rc_parent);
12901     GetWindowRect(hchild, &rc_child);
12902     SetCursorPos(rc_child.left - 10, rc_child.top - 10);
12903 
12904     /* Process messages so that the system updates its internal current
12905      * window and hittest, otherwise TrackMouseEvent calls don't have any
12906      * effect.
12907      */
12908     flush_events();
12909     flush_sequence();
12910 
12911     track_query(0, NULL, 0);
12912     track_hover(hchild, 0);
12913     track_query(0, NULL, 0);
12914 
12915     flush_events();
12916     flush_sequence();
12917 
12918     track_hover(hwnd, 0);
12919     tme.cbSize = sizeof(tme);
12920     tme.dwFlags = TME_QUERY;
12921     tme.hwndTrack = (HWND)0xdeadbeef;
12922     tme.dwHoverTime = 0xdeadbeef;
12923     SetLastError(0xdeadbeef);
12924     ret = pTrackMouseEvent(&tme);
12925     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());
12926     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize);
12927     if (!tme.dwFlags)
12928     {
12929         skip( "Cursor not inside window, skipping TrackMouseEvent tests\n" );
12930         DestroyWindow( hwnd );
12931         return;
12932     }
12933     ok(tme.dwFlags == TME_HOVER, "wrong tme.dwFlags %08x, expected TME_HOVER\n", tme.dwFlags);
12934     ok(tme.hwndTrack == hwnd, "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, hwnd);
12935     ok(tme.dwHoverTime == default_hover_time, "wrong tme.dwHoverTime %u, expected %u\n",
12936        tme.dwHoverTime, default_hover_time);
12937 
12938     pump_msg_loop_timeout(default_hover_time, FALSE);
12939     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
12940 
12941     track_query(0, NULL, 0);
12942 
12943     track_hover(hwnd, HOVER_DEFAULT);
12944     track_query(TME_HOVER, hwnd, default_hover_time);
12945 
12946     Sleep(default_hover_time / 2);
12947     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
12948     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
12949 
12950     track_query(TME_HOVER, hwnd, default_hover_time);
12951 
12952     pump_msg_loop_timeout(default_hover_time, FALSE);
12953     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
12954 
12955     track_query(0, NULL, 0);
12956 
12957     track_hover(hwnd, HOVER_DEFAULT);
12958     track_query(TME_HOVER, hwnd, default_hover_time);
12959 
12960     pump_msg_loop_timeout(default_hover_time, TRUE);
12961     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
12962 
12963     track_query(0, NULL, 0);
12964 
12965     track_hover(hwnd, HOVER_DEFAULT);
12966     track_query(TME_HOVER, hwnd, default_hover_time);
12967     track_hover_cancel(hwnd);
12968 
12969     DestroyWindow(hwnd);
12970 
12971 #undef track_hover
12972 #undef track_query
12973 #undef track_hover_cancel
12974 }
12975 
12976 
12977 static const struct message WmSetWindowRgn[] = {
12978     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
12979     { WM_NCCALCSIZE, sent|wparam, 1 },
12980     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
12981     { WM_GETTEXT, sent|defwinproc|optional },
12982     { WM_ERASEBKGND, sent|optional },
12983     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
12984     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12985     { 0 }
12986 };
12987 
12988 static const struct message WmSetWindowRgn_no_redraw[] = {
12989     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
12990     { WM_NCCALCSIZE, sent|wparam, 1 },
12991     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
12992     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12993     { 0 }
12994 };
12995 
12996 static const struct message WmSetWindowRgn_clear[] = {
12997     { WM_WINDOWPOSCHANGING, sent/*|wparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */ },
12998     { WM_NCCALCSIZE, sent|wparam, 1 },
12999     { WM_NCPAINT, sent|optional },
13000     { WM_GETTEXT, sent|defwinproc|optional },
13001     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
13002     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
13003     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
13004     { WM_NCPAINT, sent|optional },
13005     { WM_GETTEXT, sent|defwinproc|optional },
13006     { WM_ERASEBKGND, sent|optional },
13007     { WM_WINDOWPOSCHANGING, sent|optional },
13008     { WM_NCCALCSIZE, sent|optional|wparam, 1 },
13009     { WM_NCPAINT, sent|optional },
13010     { WM_GETTEXT, sent|defwinproc|optional },
13011     { WM_ERASEBKGND, sent|optional },
13012     { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
13013     { WM_NCCALCSIZE, sent|optional|wparam, 1 },
13014     { WM_NCPAINT, sent|optional },
13015     { WM_GETTEXT, sent|defwinproc|optional },
13016     { WM_ERASEBKGND, sent|optional },
13017     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
13018     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
13019     { 0 }
13020 };
13021 
13022 static void test_SetWindowRgn(void)
13023 {
13024     HRGN hrgn;
13025     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
13026                                 100, 100, 200, 200, 0, 0, 0, NULL);
13027     ok( hwnd != 0, "Failed to create overlapped window\n" );
13028 
13029     ShowWindow( hwnd, SW_SHOW );
13030     UpdateWindow( hwnd );
13031     flush_events();
13032     flush_sequence();
13033 
13034     trace("testing SetWindowRgn\n");
13035     hrgn = CreateRectRgn( 0, 0, 150, 150 );
13036     SetWindowRgn( hwnd, hrgn, TRUE );
13037     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
13038 
13039     hrgn = CreateRectRgn( 30, 30, 160, 160 );
13040     SetWindowRgn( hwnd, hrgn, FALSE );
13041     ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
13042 
13043     hrgn = CreateRectRgn( 0, 0, 180, 180 );
13044     SetWindowRgn( hwnd, hrgn, TRUE );
13045     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
13046 
13047     SetWindowRgn( hwnd, 0, TRUE );
13048     ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
13049 
13050     DestroyWindow( hwnd );
13051 }
13052 
13053 /*************************** ShowWindow() test ******************************/
13054 static const struct message WmShowNormal[] = {
13055     { WM_SHOWWINDOW, sent|wparam, 1 },
13056     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
13057     { HCBT_ACTIVATE, hook },
13058     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
13059     { HCBT_SETFOCUS, hook },
13060     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13061     { 0 }
13062 };
13063 static const struct message WmShow[] = {
13064     { WM_SHOWWINDOW, sent|wparam, 1 },
13065     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
13066     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13067     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13068     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13069     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13070     { 0 }
13071 };
13072 static const struct message WmShowNoActivate_1[] = {
13073     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
13074     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13075     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13076     { WM_MOVE, sent|defwinproc|optional },
13077     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
13078     { 0 }
13079 };
13080 static const struct message WmShowNoActivate_2[] = {
13081     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
13082     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
13083     { HCBT_ACTIVATE, hook|optional },
13084     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13085     { HCBT_SETFOCUS, hook|optional },
13086     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
13087     { WM_MOVE, sent|defwinproc },
13088     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
13089     { HCBT_SETFOCUS, hook|optional },
13090     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
13091     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
13092     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13093     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
13094     { 0 }
13095 };
13096 static const struct message WmShowNA_1[] = {
13097     { WM_SHOWWINDOW, sent|wparam, 1 },
13098     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13099     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13100     { 0 }
13101 };
13102 static const struct message WmShowNA_2[] = {
13103     { WM_SHOWWINDOW, sent|wparam, 1 },
13104     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13105     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13106     { 0 }
13107 };
13108 static const struct message WmRestore_1[] = {
13109     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
13110     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13111     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13112     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13113     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13114     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13115     { WM_MOVE, sent|defwinproc },
13116     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
13117     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
13118     { 0 }
13119 };
13120 static const struct message WmRestore_2[] = {
13121     { WM_SHOWWINDOW, sent|wparam, 1 },
13122     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
13123     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13124     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13125     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13126     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13127     { 0 }
13128 };
13129 static const struct message WmRestore_3[] = {
13130     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
13131     { WM_GETMINMAXINFO, sent },
13132     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13133     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
13134     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
13135     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
13136     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13137     { WM_MOVE, sent|defwinproc },
13138     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
13139     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
13140     { 0 }
13141 };
13142 static const struct message WmRestore_4[] = {
13143     { HCBT_MINMAX, hook|lparam|optional, 0, SW_RESTORE },
13144     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13145     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13146     { WM_MOVE, sent|defwinproc|optional },
13147     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
13148     { 0 }
13149 };
13150 static const struct message WmRestore_5[] = {
13151     { HCBT_MINMAX, hook|lparam|optional, 0, SW_SHOWNORMAL },
13152     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13153     { HCBT_ACTIVATE, hook|optional },
13154     { HCBT_SETFOCUS, hook|optional },
13155     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13156     { WM_MOVE, sent|defwinproc|optional },
13157     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
13158     { 0 }
13159 };
13160 static const struct message WmHide_1[] = {
13161     { WM_SHOWWINDOW, sent|wparam, 0 },
13162     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOACTIVATE },
13163     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOACTIVATE },
13164     { HCBT_ACTIVATE, hook|optional },
13165     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
13166     { 0 }
13167 };
13168 static const struct message WmHide_2[] = {
13169     { WM_SHOWWINDOW, sent|wparam, 0 },
13170     { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
13171     { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
13172     { HCBT_ACTIVATE, hook|optional },
13173     { 0 }
13174 };
13175 static const struct message WmHide_3[] = {
13176     { WM_SHOWWINDOW, sent|wparam, 0 },
13177     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
13178     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13179     { HCBT_SETFOCUS, hook|optional },
13180     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
13181     { 0 }
13182 };
13183 static const struct message WmShowMinimized_1[] = {
13184     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
13185     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13186     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13187     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13188     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13189     { WM_MOVE, sent|defwinproc },
13190     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
13191     { 0 }
13192 };
13193 static const struct message WmMinimize_1[] = {
13194     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
13195     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13196     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
13197     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13198     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13199     { WM_MOVE, sent|defwinproc },
13200     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
13201     { 0 }
13202 };
13203 static const struct message WmMinimize_2[] = {
13204     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
13205     { HCBT_SETFOCUS, hook|optional },
13206     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
13207     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
13208     { WM_MOVE, sent|defwinproc },
13209     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
13210     { 0 }
13211 };
13212 static const struct message WmMinimize_3[] = {
13213     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
13214     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
13215     { HCBT_ACTIVATE, hook|optional },
13216     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13217     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
13218     { WM_MOVE, sent|defwinproc },
13219     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
13220     { 0 }
13221 };
13222 static const struct message WmShowMinNoActivate[] = {
13223     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
13224     { WM_WINDOWPOSCHANGING, sent },
13225     { WM_WINDOWPOSCHANGED, sent },
13226     { WM_MOVE, sent|defwinproc|optional },
13227     { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
13228     { 0 }
13229 };
13230 static const struct message WmMinMax_1[] = {
13231     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
13232     { 0 }
13233 };
13234 static const struct message WmMinMax_2[] = {
13235     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
13236     { WM_GETMINMAXINFO, sent|optional },
13237     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED },
13238     { HCBT_ACTIVATE, hook|optional },
13239     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13240     { HCBT_SETFOCUS, hook|optional },
13241     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13242     { WM_MOVE, sent|defwinproc|optional },
13243     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MAXIMIZED },
13244     { HCBT_SETFOCUS, hook|optional },
13245     { 0 }
13246 };
13247 static const struct message WmMinMax_3[] = {
13248     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
13249     { HCBT_SETFOCUS, hook|optional },
13250     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13251     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13252     { WM_MOVE, sent|defwinproc|optional },
13253     { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
13254     { 0 }
13255 };
13256 static const struct message WmMinMax_4[] = {
13257     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
13258     { 0 }
13259 };
13260 static const struct message WmShowMaximized_1[] = {
13261     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
13262     { WM_GETMINMAXINFO, sent },
13263     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13264     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13265     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13266     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13267     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13268     { WM_MOVE, sent|defwinproc },
13269     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
13270     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
13271     { 0 }
13272 };
13273 static const struct message WmShowMaximized_2[] = {
13274     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
13275     { WM_GETMINMAXINFO, sent },
13276     { WM_WINDOWPOSCHANGING, sent|optional },
13277     { HCBT_ACTIVATE, hook|optional },
13278     { WM_WINDOWPOSCHANGED, sent|optional },
13279     { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
13280     { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
13281     { WM_WINDOWPOSCHANGING, sent|optional },
13282     { HCBT_SETFOCUS, hook|optional },
13283     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13284     { WM_MOVE, sent|defwinproc },
13285     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
13286     { HCBT_SETFOCUS, hook|optional },
13287     { 0 }
13288 };
13289 static const struct message WmShowMaximized_3[] = {
13290     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
13291     { WM_GETMINMAXINFO, sent|optional },
13292     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13293     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13294     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13295     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13296     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13297     { WM_MOVE, sent|defwinproc|optional },
13298     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
13299     { 0 }
13300 };
13301 
13302 static void test_ShowWindow(void)
13303 {
13304     /* ShowWindow commands in random order */
13305     static const struct
13306     {
13307         INT cmd; /* ShowWindow command */
13308         LPARAM ret; /* ShowWindow return value */
13309         DWORD style; /* window style after the command */
13310         const struct message *msg; /* message sequence the command produces */
13311         INT wp_cmd, wp_flags; /* window placement after the command */
13312         POINT wp_min, wp_max; /* window placement after the command */
13313         BOOL todo_msg; /* message sequence doesn't match what Wine does */
13314     } sw[] =
13315     {
13316 /*  1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal,
13317            SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
13318 /*  2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq,
13319            SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
13320 /*  3 */ { SW_HIDE, TRUE, 0, WmHide_1,
13321            SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
13322 /*  4 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13323            SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
13324 /*  5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1,
13325            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13326 /*  6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1,
13327            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13328 /*  7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1,
13329            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13330 /*  8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
13331            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13332 /*  9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1,
13333            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13334 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
13335            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13336 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1,
13337            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13338 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq,
13339            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13340 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1,
13341            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13342 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
13343            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13344 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2,
13345            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13346 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13347            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13348 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow,
13349            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13350 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
13351            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13352 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
13353            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13354 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
13355            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13356 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13357            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13358 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate,
13359            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, TRUE },
13360 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4,
13361            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13362 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13363            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13364 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
13365            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13366 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1,
13367            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13368 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2,
13369            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13370 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13371            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13372 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
13373            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13374 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1,
13375            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13376 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
13377            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13378 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3,
13379            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13380 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13381            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13382 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, /* what does this mean?! */
13383            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13384 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq,
13385            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13386 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13387            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13388 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2,
13389            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13390 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
13391            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13392 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
13393            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13394 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2,
13395            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13396 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
13397            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13398 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2,
13399            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13400 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
13401            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13402 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
13403            SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13404 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
13405            SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13406 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3,
13407            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13408 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4,
13409            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13410 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3,
13411            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13412 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq,
13413            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13414 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
13415            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13416 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
13417            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13418 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1,
13419            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13420 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13421            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13422 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3,
13423            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13424 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13425            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13426 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2,
13427            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13428 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
13429            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE }
13430     };
13431     HWND hwnd;
13432     DWORD style;
13433     LPARAM ret;
13434     INT i;
13435     WINDOWPLACEMENT wp;
13436     RECT win_rc, work_rc = {0, 0, 0, 0};
13437 
13438 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
13439     hwnd = CreateWindowExA(0, "ShowWindowClass", NULL, WS_BASE,
13440                           120, 120, 90, 90,
13441                           0, 0, 0, NULL);
13442     assert(hwnd);
13443 
13444     style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
13445     ok(style == 0, "expected style 0, got %08x\n", style);
13446 
13447     flush_events();
13448     flush_sequence();
13449 
13450     if (pGetMonitorInfoA && pMonitorFromPoint)
13451     {
13452         HMONITOR hmon;
13453         MONITORINFO mi;
13454         POINT pt = {0, 0};
13455 
13456         SetLastError(0xdeadbeef);
13457         hmon = pMonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
13458         ok(hmon != 0, "MonitorFromPoint error %u\n", GetLastError());
13459 
13460         mi.cbSize = sizeof(mi);
13461         SetLastError(0xdeadbeef);
13462         ret = pGetMonitorInfoA(hmon, &mi);
13463         ok(ret, "GetMonitorInfo error %u\n", GetLastError());
13464         trace("monitor %s, work %s\n", wine_dbgstr_rect(&mi.rcMonitor),
13465               wine_dbgstr_rect(&mi.rcWork));
13466         work_rc = mi.rcWork;
13467     }
13468 
13469     GetWindowRect(hwnd, &win_rc);
13470     OffsetRect(&win_rc, -work_rc.left, -work_rc.top);
13471 
13472     wp.length = sizeof(wp);
13473     SetLastError(0xdeadbeaf);
13474     ret = GetWindowPlacement(hwnd, &wp);
13475     ok(ret, "GetWindowPlacement error %u\n", GetLastError());
13476     ok(wp.flags == 0, "expected 0, got %#x\n", wp.flags);
13477     ok(wp.showCmd == SW_SHOWNORMAL, "expected SW_SHOWNORMAL, got %d\n", wp.showCmd);
13478     ok(wp.ptMinPosition.x == -1 && wp.ptMinPosition.y == -1,
13479        "expected -1,-1 got %d,%d\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
13480     ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
13481        "expected -1,-1 got %d,%d\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
13482     todo_wine_if (work_rc.left || work_rc.top) /* FIXME: remove once Wine is fixed */
13483     ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n", wine_dbgstr_rect(&win_rc),
13484        wine_dbgstr_rect(&wp.rcNormalPosition));
13485 
13486     for (i = 0; i < ARRAY_SIZE(sw); i++)
13487     {
13488         static const char * const sw_cmd_name[13] =
13489         {
13490             "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
13491             "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
13492             "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
13493             "SW_NORMALNA" /* 0xCC */
13494         };
13495         char comment[64];
13496         INT idx; /* index into the above array of names */
13497 
13498         idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
13499 
13500         style = GetWindowLongA(hwnd, GWL_STYLE);
13501         trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
13502         ret = ShowWindow(hwnd, sw[i].cmd);
13503         ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
13504         style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
13505         ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
13506 
13507         sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
13508         ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
13509 
13510         wp.length = sizeof(wp);
13511         SetLastError(0xdeadbeaf);
13512         ret = GetWindowPlacement(hwnd, &wp);
13513         ok(ret, "GetWindowPlacement error %u\n", GetLastError());
13514         ok(wp.flags == sw[i].wp_flags, "expected %#x, got %#x\n", sw[i].wp_flags, wp.flags);
13515         ok(wp.showCmd == sw[i].wp_cmd, "expected %d, got %d\n", sw[i].wp_cmd, wp.showCmd);
13516 
13517         /* NT moves the minimized window to -32000,-32000, win9x to 3000,3000 */
13518         if ((wp.ptMinPosition.x + work_rc.left == -32000 && wp.ptMinPosition.y + work_rc.top == -32000) ||
13519             (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000))
13520         {
13521             ok((wp.ptMinPosition.x + work_rc.left == sw[i].wp_min.x && wp.ptMinPosition.y + work_rc.top == sw[i].wp_min.y) ||
13522                (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000),
13523                "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
13524         }
13525         else
13526         {
13527             ok(wp.ptMinPosition.x == sw[i].wp_min.x && wp.ptMinPosition.y == sw[i].wp_min.y,
13528                "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
13529         }
13530 
13531         todo_wine_if(wp.ptMaxPosition.x != sw[i].wp_max.x || wp.ptMaxPosition.y != sw[i].wp_max.y)
13532         ok(wp.ptMaxPosition.x == sw[i].wp_max.x && wp.ptMaxPosition.y == sw[i].wp_max.y,
13533            "expected %d,%d got %d,%d\n", sw[i].wp_max.x, sw[i].wp_max.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y);
13534 
13535 if (0) /* FIXME: Wine behaves completely different here */
13536         ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n",
13537            wine_dbgstr_rect(&win_rc), wine_dbgstr_rect(&wp.rcNormalPosition));
13538     }
13539     DestroyWindow(hwnd);
13540     flush_events();
13541 }
13542 
13543 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13544 {
13545     struct recvd_message msg;
13546 
13547     if (ignore_message( message )) return 0;
13548 
13549     msg.hwnd = hwnd;
13550     msg.message = message;
13551     msg.flags = sent|wparam|lparam;
13552     msg.wParam = wParam;
13553     msg.lParam = lParam;
13554     msg.descr = "dialog";
13555     add_message(&msg);
13556 
13557     /* calling DefDlgProc leads to a recursion under XP */
13558 
13559     switch (message)
13560     {
13561     case WM_INITDIALOG:
13562         return lParam;
13563 
13564     case WM_GETDLGCODE:
13565         return 0;
13566     }
13567     return 1;
13568 }
13569 
13570 static WNDPROC orig_edit_proc;
13571 static LRESULT WINAPI dlg_creation_edit_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
13572 {
13573     struct recvd_message msg;
13574 
13575     if (ignore_message( message )) return 0;
13576 
13577     msg.hwnd = hwnd;
13578     msg.message = message;
13579     msg.flags = sent|wparam|lparam;
13580     msg.wParam = wp;
13581     msg.lParam = lp;
13582     msg.descr = "edit";
13583     add_message(&msg);
13584 
13585     return CallWindowProcW(orig_edit_proc, hwnd, message, wp, lp);
13586 }
13587 
13588 static INT_PTR WINAPI test_dlg_proc2(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13589 {
13590     struct recvd_message msg;
13591 
13592     if (ignore_message( message )) return 0;
13593 
13594     msg.hwnd = hwnd;
13595     msg.message = message;
13596     msg.flags = sent|wparam|lparam|parent;
13597     msg.wParam = wParam;
13598     msg.lParam = lParam;
13599     msg.descr = "dialog";
13600     add_message(&msg);
13601 
13602     if (message == WM_INITDIALOG)
13603     {
13604         orig_edit_proc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hwnd, 200),
13605                 GWLP_WNDPROC, (LONG_PTR)dlg_creation_edit_proc);
13606     }
13607 
13608     return 1;
13609 }
13610 
13611 static INT_PTR WINAPI test_dlg_proc3(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13612 {
13613     ok( 0, "should not be called since DefDlgProc is not used\n" );
13614     return 0;
13615 }
13616 
13617 static LRESULT WINAPI test_dlg_proc4(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13618 {
13619     struct recvd_message msg;
13620 
13621     if (!ignore_message( message ))
13622     {
13623         msg.hwnd = hwnd;
13624         msg.message = message;
13625         msg.flags = sent|wparam|lparam|parent;
13626         msg.wParam = wParam;
13627         msg.lParam = lParam;
13628         msg.descr = "dialog";
13629         add_message(&msg);
13630     }
13631     if (message == WM_INITDIALOG)
13632     {
13633         orig_edit_proc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hwnd, 200),
13634                 GWLP_WNDPROC, (LONG_PTR)dlg_creation_edit_proc);
13635         return 1;
13636     }
13637     return DefWindowProcW( hwnd, message, wParam, lParam );
13638 }
13639 
13640 static const struct message WmDefDlgSetFocus_1[] = {
13641     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13642     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
13643     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
13644     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
13645     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
13646     { HCBT_SETFOCUS, hook },
13647     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
13648     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13649     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
13650     { WM_SETFOCUS, sent|wparam, 0 },
13651     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
13652     { WM_CTLCOLOREDIT, sent },
13653     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
13654     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13655     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13656     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13657     { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
13658     { 0 }
13659 };
13660 static const struct message WmDefDlgSetFocus_2[] = {
13661     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13662     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
13663     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
13664     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
13665     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
13666     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13667     { WM_CTLCOLOREDIT, sent|optional }, /* XP */
13668     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13669     { 0 }
13670 };
13671 /* Creation of a dialog */
13672 static const struct message WmCreateDialogParamSeq_0[] = {
13673     { HCBT_CREATEWND, hook },
13674     { WM_NCCREATE, sent },
13675     { WM_NCCALCSIZE, sent|wparam, 0 },
13676     { WM_CREATE, sent },
13677     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13678     { WM_SIZE, sent|wparam, SIZE_RESTORED },
13679     { WM_MOVE, sent },
13680     { WM_SETFONT, sent },
13681     { WM_INITDIALOG, sent },
13682     { WM_CHANGEUISTATE, sent|optional },
13683     { 0 }
13684 };
13685 /* Creation of a dialog */
13686 static const struct message WmCreateDialogParamSeq_1[] = {
13687     { HCBT_CREATEWND, hook },
13688     { WM_NCCREATE, sent },
13689     { WM_NCCALCSIZE, sent|wparam, 0 },
13690     { WM_CREATE, sent },
13691     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13692     { WM_SIZE, sent|wparam, SIZE_RESTORED },
13693     { WM_MOVE, sent },
13694     { WM_SETFONT, sent },
13695     { WM_INITDIALOG, sent },
13696     { WM_GETDLGCODE, sent|wparam|lparam|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
13697     { HCBT_SETFOCUS, hook },
13698     { HCBT_ACTIVATE, hook },
13699     { WM_QUERYNEWPALETTE, sent|optional },
13700     { WM_PALETTEISCHANGING, sent|optional },
13701     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13702     { WM_ACTIVATEAPP, sent|wparam, 1 },
13703     { WM_NCACTIVATE, sent },
13704     { WM_ACTIVATE, sent|wparam, 1 },
13705     { WM_SETFOCUS, sent },
13706     { WM_CHANGEUISTATE, sent|optional },
13707     { 0 }
13708 };
13709 /* Creation of a dialog */
13710 static const struct message WmCreateDialogParamSeq_2[] = {
13711     { HCBT_CREATEWND, hook },
13712     { WM_NCCREATE, sent },
13713     { WM_NCCALCSIZE, sent|wparam, 0 },
13714     { WM_CREATE, sent },
13715     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13716     { WM_SIZE, sent|wparam, SIZE_RESTORED },
13717     { WM_MOVE, sent },
13718     { WM_CHANGEUISTATE, sent|optional },
13719     { 0 }
13720 };
13721 
13722 static const struct message WmCreateDialogParamSeq_3[] = {
13723     { HCBT_CREATEWND, hook },
13724     { WM_SETFONT, sent|parent },
13725     { WM_INITDIALOG, sent|parent },
13726     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13727     { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
13728     { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13729     { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13730     { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13731     { HCBT_ACTIVATE, hook },
13732     { WM_QUERYNEWPALETTE, sent|parent|optional }, /* TODO: this message should not be sent */
13733     { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13734     { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13735     { WM_WINDOWPOSCHANGED, sent|parent|wparam|optional, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13736     { WM_WINDOWPOSCHANGED, sent|parent|wparam|optional, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13737     { WM_ACTIVATEAPP, sent|parent|wparam, 1 },
13738     { WM_NCACTIVATE, sent|parent },
13739     { WM_ACTIVATE, sent|parent|wparam, 1 },
13740     { WM_SETFOCUS, sent },
13741     { WM_COMMAND, sent|parent|wparam, MAKELONG(200, EN_SETFOCUS) },
13742     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13743     { WM_USER, sent|parent },
13744     { WM_CHANGEUISTATE, sent|parent|optional },
13745     { 0 }
13746 };
13747 
13748 static const struct message WmCreateDialogParamSeq_4[] = {
13749     { HCBT_CREATEWND, hook },
13750     { WM_NCCREATE, sent|parent },
13751     { WM_NCCALCSIZE, sent|parent|wparam, 0 },
13752     { WM_CREATE, sent|parent },
13753     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13754     { WM_SIZE, sent|parent|wparam, SIZE_RESTORED },
13755     { WM_MOVE, sent|parent },
13756     { WM_SETFONT, sent|parent },
13757     { WM_INITDIALOG, sent|parent },
13758     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13759     { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
13760     { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13761     { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13762     { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13763     { HCBT_ACTIVATE, hook },
13764     { WM_QUERYNEWPALETTE, sent|parent|optional }, /* TODO: this message should not be sent */
13765     { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13766     { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13767     { WM_ACTIVATEAPP, sent|parent|wparam, 1 },
13768     { WM_NCACTIVATE, sent|parent },
13769     { WM_ACTIVATE, sent|parent|wparam, 1 },
13770     { HCBT_SETFOCUS, hook },
13771     { WM_SETFOCUS, sent|parent },
13772     { WM_KILLFOCUS, sent|parent },
13773     { WM_SETFOCUS, sent },
13774     { WM_COMMAND, sent|parent|wparam, MAKELONG(200, EN_SETFOCUS) },
13775     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13776     { WM_USER, sent|parent },
13777     { WM_CHANGEUISTATE, sent|parent|optional },
13778     { WM_UPDATEUISTATE, sent|parent|optional },
13779     { WM_UPDATEUISTATE, sent|optional },
13780     { 0 }
13781 };
13782 
13783 static void test_dialog_messages(void)
13784 {
13785     WNDCLASSA cls;
13786     HWND hdlg, hedit1, hedit2, hfocus, parent, child, child2;
13787     LRESULT ret;
13788 
13789 #define set_selection(hctl, start, end) \
13790     ret = SendMessageA(hctl, EM_SETSEL, start, end); \
13791     ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
13792 
13793 #define check_selection(hctl, start, end) \
13794     ret = SendMessageA(hctl, EM_GETSEL, 0, 0); \
13795     ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
13796 
13797     subclass_edit();
13798 
13799     hdlg = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
13800                           WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
13801                           0, 0, 100, 100, 0, 0, 0, NULL);
13802     ok(hdlg != 0, "Failed to create custom dialog window\n");
13803 
13804     hedit1 = CreateWindowExA(0, "my_edit_class", NULL,
13805                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
13806                            0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
13807     ok(hedit1 != 0, "Failed to create edit control\n");
13808     hedit2 = CreateWindowExA(0, "my_edit_class", NULL,
13809                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
13810                            0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
13811     ok(hedit2 != 0, "Failed to create edit control\n");
13812 
13813     SendMessageA(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
13814     SendMessageA(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
13815 
13816     hfocus = GetFocus();
13817     ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
13818 
13819     SetFocus(hedit2);
13820     hfocus = GetFocus();
13821     ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
13822 
13823     check_selection(hedit1, 0, 0);
13824     check_selection(hedit2, 0, 0);
13825 
13826     set_selection(hedit2, 0, -1);
13827     check_selection(hedit2, 0, 3);
13828 
13829     SetFocus(0);
13830     hfocus = GetFocus();
13831     ok(hfocus == 0, "wrong focus %p\n", hfocus);
13832 
13833     flush_sequence();
13834     ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
13835     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
13836     ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
13837 
13838     hfocus = GetFocus();
13839     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
13840 
13841     check_selection(hedit1, 0, 5);
13842     check_selection(hedit2, 0, 3);
13843 
13844     flush_sequence();
13845     ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
13846     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
13847     ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
13848 
13849     hfocus = GetFocus();
13850     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
13851 
13852     check_selection(hedit1, 0, 5);
13853     check_selection(hedit2, 0, 3);
13854 
13855     EndDialog(hdlg, 0);
13856     DestroyWindow(hedit1);
13857     DestroyWindow(hedit2);
13858     DestroyWindow(hdlg);
13859     flush_sequence();
13860 
13861 #undef set_selection
13862 #undef check_selection
13863 
13864     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
13865     cls.lpszClassName = "MyDialogClass";
13866     cls.hInstance = GetModuleHandleA(NULL);
13867     /* need a cast since a dlgproc is used as a wndproc */
13868     cls.lpfnWndProc = test_dlg_proc;
13869     if (!RegisterClassA(&cls)) assert(0);
13870 
13871     SetFocus(0);
13872     flush_sequence();
13873     hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
13874     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13875     ok_sequence(WmCreateDialogParamSeq_0, "CreateDialogParam_0", FALSE);
13876     hfocus = GetFocus();
13877     ok(hfocus == 0, "wrong focus %p\n", hfocus);
13878     EndDialog(hdlg, 0);
13879     DestroyWindow(hdlg);
13880     flush_sequence();
13881 
13882     SetFocus(0);
13883     flush_sequence();
13884     hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 1);
13885     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13886     ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
13887     hfocus = GetFocus();
13888     ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
13889     EndDialog(hdlg, 0);
13890     DestroyWindow(hdlg);
13891     flush_sequence();
13892 
13893     hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
13894     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13895     ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
13896     EndDialog(hdlg, 0);
13897     DestroyWindow(hdlg);
13898     flush_sequence();
13899 
13900     hdlg = CreateDialogParamA(0, "FOCUS_TEST_DIALOG_3", 0, test_dlg_proc2, 0);
13901     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13902     ok_sequence(WmCreateDialogParamSeq_3, "CreateDialogParam_3", TRUE);
13903     EndDialog(hdlg, 0);
13904     DestroyWindow(hdlg);
13905     flush_sequence();
13906 
13907     UnregisterClassA( cls.lpszClassName, cls.hInstance );
13908     cls.lpfnWndProc = test_dlg_proc4;
13909     ok( RegisterClassA(&cls), "failed to register class again\n" );
13910     hdlg = CreateDialogParamA(0, "FOCUS_TEST_DIALOG_4", 0, test_dlg_proc3, 0);
13911     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13912     ok_sequence(WmCreateDialogParamSeq_4, "CreateDialogParam_4", TRUE);
13913     EndDialog(hdlg, 0);
13914     DestroyWindow(hdlg);
13915     flush_sequence();
13916 
13917     UnregisterClassA(cls.lpszClassName, cls.hInstance);
13918 
13919     parent = CreateWindowExA(0, "TestParentClass", "Test parent",
13920                              WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13921                              100, 100, 200, 200, 0, 0, 0, NULL);
13922     ok (parent != 0, "Failed to create parent window\n");
13923 
13924     /* This child has no parent set. We will later call SetParent on it,
13925      * so that it will have a parent set, but no WS_CHILD style. */
13926     child = CreateWindowExA(0, "TestWindowClass", "Test child",
13927                             WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13928                             100, 100, 200, 200, 0, 0, 0, NULL);
13929     ok (child != 0, "Failed to create child window\n");
13930 
13931     /* This is a regular child window. When used as an owner, the other
13932      * child window will be used. */
13933     child2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2",
13934                              WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CHILD,
13935                              100, 100, 200, 200, child, 0, 0, NULL);
13936     ok (child2 != 0, "Failed to create child window\n");
13937 
13938     SetParent(child, parent);
13939     SetFocus(child);
13940 
13941     flush_sequence();
13942     DialogBoxA( 0, "TEST_DIALOG", child2, TestModalDlgProc2 );
13943     ok_sequence(WmModalDialogSeq_2, "ModalDialog2", TRUE);
13944 
13945     DestroyWindow(child2);
13946     DestroyWindow(child);
13947     DestroyWindow(parent);
13948     flush_sequence();
13949 }
13950 
13951 static void test_enddialog_seq(HWND dialog, HWND owner)
13952 {
13953     const struct message seq[] = {
13954         { WM_ENABLE, sent },
13955         { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13956         { HCBT_ACTIVATE, hook|wparam, (WPARAM)owner },
13957         { WM_NCACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13958         { WM_ACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13959         /* FIXME: Following two are optional because Wine sends WM_QUERYNEWPALETTE instead of WM_WINDOWPOSCHANGING */
13960         { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13961         { WM_QUERYNEWPALETTE, sent|optional },
13962         { WM_NCACTIVATE, sent|wparam|lparam, WA_ACTIVE, (LPARAM)dialog },
13963         { WM_GETTEXT, sent|optional|defwinproc },
13964         { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, (LPARAM)dialog },
13965         { HCBT_SETFOCUS, hook|wparam, (WPARAM)owner },
13966         { WM_KILLFOCUS, sent|wparam, (WPARAM)owner },
13967         { WM_SETFOCUS, sent|defwinproc|wparam, (WPARAM)dialog },
13968         { 0 }
13969     };
13970 
13971     flush_sequence();
13972     EndDialog(dialog, 0);
13973     ok_sequence(seq, "EndDialog", FALSE);
13974 }
13975 
13976 static void test_enddialog_seq2(HWND dialog, HWND owner)
13977 {
13978     const struct message seq[] = {
13979         { WM_ENABLE, parent|sent },
13980         { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13981         { HCBT_ACTIVATE, hook|wparam, (WPARAM)owner },
13982         { WM_NCACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13983         { WM_ACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13984         { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13985         { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13986         { HCBT_SETFOCUS, hook|wparam, (WPARAM)owner },
13987         { WM_KILLFOCUS, sent|wparam, (WPARAM)owner },
13988         { WM_SETFOCUS, sent|parent|defwinproc|wparam, (WPARAM)dialog },
13989         { 0 }
13990     };
13991 
13992     flush_sequence();
13993     EndDialog(dialog, 0);
13994     ok_sequence(seq, "EndDialog2", FALSE);
13995 }
13996 
13997 static void test_EndDialog(void)
13998 {
13999     HWND hparent, hother, hactive, hdlg, hchild;
14000     WNDCLASSA cls;
14001 
14002     hparent = CreateWindowExA(0, "TestParentClass", "Test parent",
14003                               WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_DISABLED,
14004                               100, 100, 200, 200, 0, 0, 0, NULL);
14005     ok (hparent != 0, "Failed to create parent window\n");
14006 
14007     hother = CreateWindowExA(0, "TestParentClass", "Test parent 2",
14008                               WS_OVERLAPPEDWINDOW | WS_VISIBLE,
14009                               200, 100, 200, 200, 0, 0, 0, NULL);
14010     ok (hother != 0, "Failed to create parent window\n");
14011 
14012     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
14013     cls.lpszClassName = "MyDialogClass";
14014     cls.hInstance = GetModuleHandleA(NULL);
14015     cls.lpfnWndProc = test_dlg_proc;
14016     if (!RegisterClassA(&cls)) assert(0);
14017 
14018     flush_sequence();
14019     SetForegroundWindow(hother);
14020     hactive = GetForegroundWindow();
14021     ok(hother == hactive, "Wrong window has focus (%p != %p)\n", hother, hactive);
14022 
14023     /* create a dialog where the parent is disabled, this parent should be
14024      * enabled and receive focus when dialog exits */
14025     hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hparent, test_dlg_proc, 0);
14026     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
14027     SetForegroundWindow(hdlg);
14028     hactive = GetForegroundWindow();
14029     ok(hdlg == hactive, "Wrong window has focus (%p != %p)\n", hdlg, hactive);
14030     EndDialog(hdlg, 0);
14031     ok(IsWindowEnabled(hparent), "parent is not enabled\n");
14032     hactive = GetForegroundWindow();
14033     ok(hparent == hactive, "Wrong window has focus (parent != active) (active: %p, parent: %p, dlg: %p, other: %p)\n", hactive, hparent, hdlg, hother);
14034     DestroyWindow(hdlg);
14035     flush_sequence();
14036 
14037     /* create a dialog where the parent is disabled and set active window to other window before calling EndDialog */
14038     EnableWindow(hparent, FALSE);
14039     hdlg = CreateWindowExA(0, "TestDialogClass", NULL,
14040                           WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
14041                           0, 0, 100, 100, hparent, 0, 0, NULL);
14042     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
14043     flush_sequence();
14044     SetForegroundWindow(hother);
14045     flush_sequence();
14046     hactive = GetForegroundWindow();
14047     ok(hactive == hother, "Wrong foreground (%p != %p)\n", hactive, hother);
14048     hactive = GetActiveWindow();
14049     ok(hactive == hother, "Wrong active window (%p != %p)\n", hactive, hother);
14050     EndDialog(hdlg, 0);
14051     ok(IsWindowEnabled(hparent), "parent is not enabled\n");
14052     hactive = GetForegroundWindow();
14053     ok(hother == hactive, "Wrong window has focus (other != active) (active: %p, parent: %p, dlg: %p, other: %p)\n", hactive, hparent, hdlg, hother);
14054     DestroyWindow(hdlg);
14055     flush_sequence();
14056 
14057     DestroyWindow( hparent );
14058 
14059     hparent = CreateWindowExA(0, "TestParentClass", "Test parent",
14060                               WS_POPUP | WS_VISIBLE | WS_DISABLED,
14061                               100, 100, 200, 200, 0, 0, 0, NULL);
14062     ok (hparent != 0, "Failed to create parent window\n");
14063 
14064     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
14065                              WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_DISABLED,
14066                              0, 0, 0, 0, 0, 0, 0, NULL);
14067     ok (hchild != 0, "Failed to create child window\n");
14068 
14069     SetParent(hchild, hparent);
14070 
14071     flush_sequence();
14072     SetForegroundWindow(hother);
14073     hactive = GetForegroundWindow();
14074     ok(hother == hactive, "Wrong foreground window (%p != %p)\n", hother, hactive);
14075 
14076     hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hchild, test_dlg_proc, 0);
14077     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
14078 
14079     SetForegroundWindow(hdlg);
14080     test_enddialog_seq(hdlg, hchild);
14081 
14082     hactive = GetForegroundWindow();
14083     ok(hactive == hchild, "Wrong foreground window (active: %p, parent: %p, dlg: %p, other: %p child: %p)\n", hactive, hparent, hdlg, hother, hchild);
14084 
14085     DestroyWindow(hdlg);
14086 
14087     /* Now set WS_CHILD style flag so that it's a real child and its parent will be dialog's owner. */
14088     SetWindowLongW(hchild, GWL_STYLE, GetWindowLongW(hchild, GWL_STYLE) | WS_CHILD);
14089 
14090     SetForegroundWindow(hother);
14091     hactive = GetForegroundWindow();
14092     ok(hother == hactive, "Wrong foreground window (%p != %p)\n", hother, hactive);
14093 
14094     hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hchild, test_dlg_proc, 0);
14095     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
14096 
14097     SetForegroundWindow(hdlg);
14098     test_enddialog_seq2(hdlg, hparent);
14099 
14100     hactive = GetForegroundWindow();
14101     ok(hactive == hparent, "Wrong foreground window (active: %p, parent: %p, dlg: %p, other: %p child: %p)\n", hactive, hparent, hdlg, hother, hchild);
14102     DestroyWindow(hdlg);
14103     DestroyWindow(hchild);
14104     DestroyWindow(hparent);
14105     DestroyWindow(hother);
14106     flush_sequence();
14107 
14108     UnregisterClassA(cls.lpszClassName, cls.hInstance);
14109 }
14110 
14111 static void test_nullCallback(void)
14112 {
14113     HWND hwnd;
14114 
14115     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
14116                            100, 100, 200, 200, 0, 0, 0, NULL);
14117     ok (hwnd != 0, "Failed to create overlapped window\n");
14118 
14119     SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
14120     flush_events();
14121     DestroyWindow(hwnd);
14122 }
14123 
14124 /* SetActiveWindow( 0 ) hwnd visible */
14125 static const struct message SetActiveWindowSeq0[] =
14126 {
14127     { HCBT_ACTIVATE, hook|optional },
14128     { WM_NCACTIVATE, sent|wparam, 0 },
14129     { WM_GETTEXT, sent|defwinproc|optional },
14130     { WM_ACTIVATE, sent|wparam, 0 },
14131     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
14132     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
14133     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
14134     { WM_KILLFOCUS, sent|optional },
14135     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
14136     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
14137     { WM_NCACTIVATE, sent|wparam|optional, 1 },
14138     { WM_GETTEXT, sent|defwinproc|optional },
14139     { WM_ACTIVATE, sent|wparam|optional, 1 },
14140     { HCBT_SETFOCUS, hook|optional },
14141     { WM_KILLFOCUS, sent|defwinproc|optional },
14142     { WM_IME_SETCONTEXT, sent|defwinproc|optional },
14143     { WM_IME_SETCONTEXT, sent|defwinproc|optional },
14144     { WM_IME_SETCONTEXT, sent|optional },
14145     { WM_IME_SETCONTEXT, sent|optional },
14146     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
14147     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
14148     { WM_SETFOCUS, sent|defwinproc|optional },
14149     { WM_GETTEXT, sent|optional },
14150     { 0 }
14151 };
14152 /* SetActiveWindow( hwnd ) hwnd visible */
14153 static const struct message SetActiveWindowSeq1[] =
14154 {
14155     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
14156     { 0 }
14157 };
14158 /* SetActiveWindow( popup ) hwnd visible, popup visible */
14159 static const struct message SetActiveWindowSeq2[] =
14160 {
14161     { HCBT_ACTIVATE, hook },
14162     { WM_NCACTIVATE, sent|wparam, 0 },
14163     { WM_GETTEXT, sent|defwinproc|optional },
14164     { WM_ACTIVATE, sent|wparam, 0 },
14165     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
14166     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
14167     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
14168     { WM_NCPAINT, sent|optional },
14169     { WM_GETTEXT, sent|defwinproc|optional },
14170     { WM_ERASEBKGND, sent|optional },
14171     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14172     { WM_NCACTIVATE, sent|wparam, 1 },
14173     { WM_GETTEXT, sent|defwinproc|optional },
14174     { WM_ACTIVATE, sent|wparam, 1 },
14175     { HCBT_SETFOCUS, hook },
14176     { WM_KILLFOCUS, sent|defwinproc },
14177     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
14178     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
14179     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
14180     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
14181     { WM_SETFOCUS, sent|defwinproc },
14182     { WM_GETTEXT, sent|optional },
14183     { 0 }
14184 };
14185 
14186 /* SetActiveWindow( hwnd ) hwnd not visible */
14187 static const struct message SetActiveWindowSeq3[] =
14188 {
14189     { HCBT_ACTIVATE, hook },
14190     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
14191     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
14192     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
14193     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14194     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14195     { WM_ACTIVATEAPP, sent|wparam, 1 },
14196     { WM_ACTIVATEAPP, sent|wparam, 1 },
14197     { WM_NCACTIVATE, sent|wparam, 1 },
14198     { WM_ACTIVATE, sent|wparam, 1 },
14199     { HCBT_SETFOCUS, hook },
14200     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
14201     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
14202     { WM_SETFOCUS, sent|defwinproc },
14203     { 0 }
14204 };
14205 /* SetActiveWindow( popup ) hwnd not visible, popup not visible */
14206 static const struct message SetActiveWindowSeq4[] =
14207 {
14208     { HCBT_ACTIVATE, hook },
14209     { WM_NCACTIVATE, sent|wparam, 0 },
14210     { WM_GETTEXT, sent|defwinproc|optional },
14211     { WM_ACTIVATE, sent|wparam, 0 },
14212     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
14213     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
14214     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
14215     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14216     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14217     { WM_NCACTIVATE, sent|wparam, 1 },
14218     { WM_GETTEXT, sent|defwinproc|optional },
14219     { WM_ACTIVATE, sent|wparam, 1 },
14220     { HCBT_SETFOCUS, hook },
14221     { WM_KILLFOCUS, sent|defwinproc },
14222     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
14223     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
14224     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
14225     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
14226     { WM_SETFOCUS, sent|defwinproc },
14227     { 0 }
14228 };
14229 
14230 
14231 static void test_SetActiveWindow(void)
14232 {
14233     HWND hwnd, popup, ret;
14234 
14235     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
14236                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
14237                            100, 100, 200, 200, 0, 0, 0, NULL);
14238 
14239     popup = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
14240                            WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_POPUP,
14241                            100, 100, 200, 200, hwnd, 0, 0, NULL);
14242 
14243     ok(hwnd != 0, "Failed to create overlapped window\n");
14244     ok(popup != 0, "Failed to create popup window\n");
14245     SetForegroundWindow( popup );
14246     flush_sequence();
14247 
14248     trace("SetActiveWindow(0)\n");
14249     ret = SetActiveWindow(0);
14250     ok( ret == popup, "Failed to SetActiveWindow(0)\n");
14251     ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", FALSE);
14252     flush_sequence();
14253 
14254     trace("SetActiveWindow(hwnd), hwnd visible\n");
14255     ret = SetActiveWindow(hwnd);
14256     if (ret == hwnd) ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE);
14257     flush_sequence();
14258 
14259     trace("SetActiveWindow(popup), hwnd visible, popup visible\n");
14260     ret = SetActiveWindow(popup);
14261     ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n");
14262     ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visible", FALSE);
14263     flush_sequence();
14264 
14265     ShowWindow(hwnd, SW_HIDE);
14266     ShowWindow(popup, SW_HIDE);
14267     flush_sequence();
14268 
14269     trace("SetActiveWindow(hwnd), hwnd not visible\n");
14270     ret = SetActiveWindow(hwnd);
14271     ok( ret == NULL, "SetActiveWindow(hwnd), hwnd not visible, previous is %p\n", ret );
14272     ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE);
14273     flush_sequence();
14274 
14275     trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n");
14276     ret = SetActiveWindow(popup);
14277     ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n");
14278     ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visible", TRUE);
14279     flush_sequence();
14280 
14281     trace("done\n");
14282 
14283     DestroyWindow(hwnd);
14284 }
14285 
14286 static const struct message SetForegroundWindowSeq[] =
14287 {
14288     { WM_NCACTIVATE, sent|wparam, 0 },
14289     { WM_GETTEXT, sent|defwinproc|optional },
14290     { WM_ACTIVATE, sent|wparam, 0 },
14291     { WM_ACTIVATEAPP, sent|wparam, 0 },
14292     { WM_KILLFOCUS, sent },
14293     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
14294     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
14295     { 0 }
14296 };
14297 
14298 static void test_SetForegroundWindow(void)
14299 {
14300     HWND hwnd;
14301 
14302     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
14303                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
14304                            100, 100, 200, 200, 0, 0, 0, NULL);
14305     ok (hwnd != 0, "Failed to create overlapped window\n");
14306     SetForegroundWindow( hwnd );
14307     flush_sequence();
14308 
14309     trace("SetForegroundWindow( 0 )\n");
14310     SetForegroundWindow( 0 );
14311     ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
14312     trace("SetForegroundWindow( GetDesktopWindow() )\n");
14313     SetForegroundWindow( GetDesktopWindow() );
14314     ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
14315                                         "foreground top level window", FALSE);
14316     trace("done\n");
14317 
14318     DestroyWindow(hwnd);
14319 }
14320 
14321 static DWORD get_input_codepage( void )
14322 {
14323     DWORD cp;
14324     int ret;
14325     HKL hkl = GetKeyboardLayout( 0 );
14326 
14327     ret = GetLocaleInfoW( LOWORD(hkl), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
14328                           (WCHAR *)&cp, sizeof(cp) / sizeof(WCHAR) );
14329     if (!ret) cp = CP_ACP;
14330     return cp;
14331 }
14332 
14333 static void test_dbcs_wm_char(void)
14334 {
14335     BYTE dbch[2];
14336     WCHAR wch, bad_wch;
14337     HWND hwnd, hwnd2;
14338     MSG msg;
14339     DWORD time;
14340     POINT pt;
14341     DWORD_PTR res;
14342     CPINFOEXA cpinfo;
14343     UINT i, j, k;
14344     struct message wmCharSeq[2];
14345     BOOL ret;
14346     DWORD cp = get_input_codepage();
14347 
14348     if (!pGetCPInfoExA)
14349     {
14350         win_skip("GetCPInfoExA is not available\n");
14351         return;
14352     }
14353 
14354     pGetCPInfoExA( cp, 0, &cpinfo );
14355     if (cpinfo.MaxCharSize != 2)
14356     {
14357         skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
14358         return;
14359     }
14360 
14361     dbch[0] = dbch[1] = 0;
14362     wch = 0;
14363     bad_wch = cpinfo.UnicodeDefaultChar;
14364     for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
14365         for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
14366             for (k = 128; k <= 255; k++)
14367             {
14368                 char str[2];
14369                 WCHAR wstr[2];
14370                 str[0] = j;
14371                 str[1] = k;
14372                 if (MultiByteToWideChar( cp, 0, str, 2, wstr, 2 ) == 1 &&
14373                     WideCharToMultiByte( cp, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
14374                     (BYTE)str[0] == j && (BYTE)str[1] == k &&
14375                     HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
14376                 {
14377                     dbch[0] = j;
14378                     dbch[1] = k;
14379                     wch = wstr[0];
14380                     break;
14381                 }
14382             }
14383 
14384     if (!wch)
14385     {
14386         skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
14387         return;
14388     }
14389     trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
14390            dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
14391 
14392     hwnd = CreateWindowExW(0, testWindowClassW, NULL,
14393                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
14394     hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
14395                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
14396     ok (hwnd != 0, "Failed to create overlapped window\n");
14397     ok (hwnd2 != 0, "Failed to create overlapped window\n");
14398     flush_sequence();
14399 
14400     memset( wmCharSeq, 0, sizeof(wmCharSeq) );
14401     wmCharSeq[0].message = WM_CHAR;
14402     wmCharSeq[0].flags = sent|wparam;
14403     wmCharSeq[0].wParam = wch;
14404 
14405     /* posted message */
14406     PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14407     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14408     ok( !ret, "got message %x\n", msg.message );
14409     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14410     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14411     ok( ret, "no message\n" );
14412     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14413     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
14414     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14415     ok( !ret, "got message %x\n", msg.message );
14416 
14417     /* posted thread message */
14418     PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
14419     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14420     ok( !ret, "got message %x\n", msg.message );
14421     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14422     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14423     ok( ret, "no message\n" );
14424     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14425     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
14426     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14427     ok( !ret, "got message %x\n", msg.message );
14428 
14429     /* sent message */
14430     flush_sequence();
14431     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14432     ok_sequence( WmEmptySeq, "no messages", FALSE );
14433     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14434     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14435     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14436     ok( !ret, "got message %x\n", msg.message );
14437 
14438     /* sent message with timeout */
14439     flush_sequence();
14440     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
14441     ok_sequence( WmEmptySeq, "no messages", FALSE );
14442     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
14443     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14444     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14445     ok( !ret, "got message %x\n", msg.message );
14446 
14447     /* sent message with timeout and callback */
14448     flush_sequence();
14449     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
14450     ok_sequence( WmEmptySeq, "no messages", FALSE );
14451     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
14452     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14453     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14454     ok( !ret, "got message %x\n", msg.message );
14455 
14456     /* sent message with callback */
14457     flush_sequence();
14458     SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14459     ok_sequence( WmEmptySeq, "no messages", FALSE );
14460     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
14461     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14462     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14463     ok( !ret, "got message %x\n", msg.message );
14464 
14465     /* direct window proc call */
14466     flush_sequence();
14467     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
14468     ok_sequence( WmEmptySeq, "no messages", FALSE );
14469     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
14470     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14471 
14472     /* dispatch message */
14473     msg.hwnd = hwnd;
14474     msg.message = WM_CHAR;
14475     msg.wParam = dbch[0];
14476     msg.lParam = 0;
14477     DispatchMessageA( &msg );
14478     ok_sequence( WmEmptySeq, "no messages", FALSE );
14479     msg.wParam = dbch[1];
14480     DispatchMessageA( &msg );
14481     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14482 
14483     /* window handle is irrelevant */
14484     flush_sequence();
14485     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
14486     ok_sequence( WmEmptySeq, "no messages", FALSE );
14487     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14488     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14489     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14490     ok( !ret, "got message %x\n", msg.message );
14491 
14492     /* interleaved post and send */
14493     flush_sequence();
14494     PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
14495     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
14496     ok_sequence( WmEmptySeq, "no messages", FALSE );
14497     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14498     ok( !ret, "got message %x\n", msg.message );
14499     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14500     ok_sequence( WmEmptySeq, "no messages", FALSE );
14501     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14502     ok( ret, "no message\n" );
14503     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14504     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
14505     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14506     ok( !ret, "got message %x\n", msg.message );
14507     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14508     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14509     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14510     ok( !ret, "got message %x\n", msg.message );
14511 
14512     /* interleaved sent message and winproc */
14513     flush_sequence();
14514     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14515     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
14516     ok_sequence( WmEmptySeq, "no messages", FALSE );
14517     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14518     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14519     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
14520     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14521 
14522     /* interleaved winproc and dispatch */
14523     msg.hwnd = hwnd;
14524     msg.message = WM_CHAR;
14525     msg.wParam = dbch[0];
14526     msg.lParam = 0;
14527     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
14528     DispatchMessageA( &msg );
14529     ok_sequence( WmEmptySeq, "no messages", FALSE );
14530     msg.wParam = dbch[1];
14531     DispatchMessageA( &msg );
14532     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14533     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
14534     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14535 
14536     /* interleaved sends */
14537     flush_sequence();
14538     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14539     SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
14540     ok_sequence( WmEmptySeq, "no messages", FALSE );
14541     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
14542     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14543     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14544     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14545 
14546     /* dbcs WM_CHAR */
14547     flush_sequence();
14548     SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
14549     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14550     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14551     ok( !ret, "got message %x\n", msg.message );
14552 
14553     /* other char messages are not magic */
14554     PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
14555     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14556     ok( ret, "no message\n" );
14557     ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
14558     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
14559     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14560     ok( !ret, "got message %x\n", msg.message );
14561     PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
14562     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14563     ok( ret, "no message\n" );
14564     ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
14565     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
14566     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14567     ok( !ret, "got message %x\n", msg.message );
14568 
14569     /* test retrieving messages */
14570 
14571     PostMessageW( hwnd, WM_CHAR, wch, 0 );
14572     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14573     ok( ret, "no message\n" );
14574     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14575     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14576     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14577     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14578     ok( ret, "no message\n" );
14579     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14580     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14581     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14582     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14583     ok( !ret, "got message %x\n", msg.message );
14584 
14585     /* message filters */
14586     PostMessageW( hwnd, WM_CHAR, wch, 0 );
14587     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14588     ok( ret, "no message\n" );
14589     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14590     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14591     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14592     /* message id is filtered, hwnd is not */
14593     ret = PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE );
14594     ok( !ret, "no message\n" );
14595     ret = PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE );
14596     ok( ret, "no message\n" );
14597     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14598     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14599     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14600     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14601     ok( !ret, "got message %x\n", msg.message );
14602 
14603     /* mixing GetMessage and PostMessage */
14604     PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
14605     ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
14606     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14607     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14608     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14609     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
14610     time = msg.time;
14611     pt = msg.pt;
14612     ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time );
14613     ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
14614     ok( ret, "no message\n" );
14615     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14616     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14617     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14618     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
14619     ok( msg.time == time, "bad time %x/%x\n", msg.time, time );
14620     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 );
14621     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14622     ok( !ret, "got message %x\n", msg.message );
14623 
14624     /* without PM_REMOVE */
14625     PostMessageW( hwnd, WM_CHAR, wch, 0 );
14626     ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
14627     ok( ret, "no message\n" );
14628     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14629     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14630     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14631     ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
14632     ok( ret, "no message\n" );
14633     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14634     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14635     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14636     ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
14637     ok( ret, "no message\n" );
14638     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14639     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14640     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14641     ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
14642     ok( ret, "no message\n" );
14643     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14644     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14645     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14646     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14647     ok( !ret, "got message %x\n", msg.message );
14648 
14649     DestroyWindow(hwnd);
14650     DestroyWindow(hwnd2);
14651 }
14652 
14653 static void test_unicode_wm_char(void)
14654 {
14655     HWND hwnd;
14656     MSG msg;
14657     struct message seq[2];
14658     HKL hkl_orig, hkl_greek;
14659     DWORD cp;
14660     LCID thread_locale;
14661 
14662     hkl_orig = GetKeyboardLayout( 0 );
14663     GetLocaleInfoW( LOWORD( hkl_orig ), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, (WCHAR*)&cp, sizeof(cp) / sizeof(WCHAR) );
14664     if (cp != 1252)
14665     {
14666         skip( "Default codepage %d\n", cp );
14667         return;
14668     }
14669 
14670     hkl_greek = LoadKeyboardLayoutA( "00000408", 0 );
14671     if (!hkl_greek || hkl_greek == hkl_orig /* win2k */)
14672     {
14673         skip( "Unable to load Greek keyboard layout\n" );
14674         return;
14675     }
14676 
14677     hwnd = CreateWindowExW( 0, testWindowClassW, NULL, WS_OVERLAPPEDWINDOW,
14678                             100, 100, 200, 200, 0, 0, 0, NULL );
14679     flush_sequence();
14680 
14681     PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
14682 
14683     while (GetMessageW( &msg, hwnd, 0, 0 ))
14684     {
14685         if (!ignore_message( msg.message )) break;
14686     }
14687 
14688     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14689     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14690     ok( msg.wParam == 0x3b1, "bad wparam %lx\n", msg.wParam );
14691     ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
14692 
14693     DispatchMessageW( &msg );
14694 
14695     memset( seq, 0, sizeof(seq) );
14696     seq[0].message = WM_CHAR;
14697     seq[0].flags = sent|wparam;
14698     seq[0].wParam = 0x3b1;
14699 
14700     ok_sequence( seq, "unicode WM_CHAR", FALSE );
14701 
14702     flush_sequence();
14703 
14704     /* greek alpha -> 'a' in cp1252 */
14705     PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
14706 
14707     ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
14708     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14709     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14710     ok( msg.wParam == 0x61, "bad wparam %lx\n", msg.wParam );
14711     ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
14712 
14713     DispatchMessageA( &msg );
14714 
14715     seq[0].wParam = 0x61;
14716     ok_sequence( seq, "unicode WM_CHAR", FALSE );
14717 
14718     thread_locale = GetThreadLocale();
14719     ActivateKeyboardLayout( hkl_greek, 0 );
14720     ok( GetThreadLocale() == thread_locale, "locale changed from %08x to %08x\n",
14721         thread_locale, GetThreadLocale() );
14722 
14723     flush_sequence();
14724 
14725     /* greek alpha -> 0xe1 in cp1253 */
14726     PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
14727 
14728     ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
14729     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14730     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14731     ok( msg.wParam == 0xe1, "bad wparam %lx\n", msg.wParam );
14732     ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
14733 
14734     DispatchMessageA( &msg );
14735 
14736     seq[0].wParam = 0x3b1;
14737     ok_sequence( seq, "unicode WM_CHAR", FALSE );
14738 
14739     DestroyWindow( hwnd );
14740     ActivateKeyboardLayout( hkl_orig, 0 );
14741     UnloadKeyboardLayout( hkl_greek );
14742 }
14743 
14744 #define ID_LISTBOX 0x000f
14745 
14746 static const struct message wm_lb_setcursel_0[] =
14747 {
14748     { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
14749     { WM_CTLCOLORLISTBOX, sent|parent },
14750     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
14751     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
14752     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
14753     { 0 }
14754 };
14755 static const struct message wm_lb_setcursel_1[] =
14756 {
14757     { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
14758     { WM_CTLCOLORLISTBOX, sent|parent },
14759     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
14760     { WM_CTLCOLORLISTBOX, sent|parent },
14761     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
14762     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
14763     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
14764     { 0 }
14765 };
14766 static const struct message wm_lb_setcursel_2[] =
14767 {
14768     { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
14769     { WM_CTLCOLORLISTBOX, sent|parent },
14770     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
14771     { WM_CTLCOLORLISTBOX, sent|parent },
14772     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
14773     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
14774     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
14775     { 0 }
14776 };
14777 static const struct message wm_lb_click_0[] =
14778 {
14779     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
14780     { HCBT_SETFOCUS, hook },
14781     { WM_KILLFOCUS, sent|parent },
14782     { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
14783     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
14784     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
14785     { WM_SETFOCUS, sent|defwinproc },
14786 
14787     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
14788     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
14789     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
14790     { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
14791     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
14792 
14793     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
14794     { WM_CTLCOLORLISTBOX, sent|parent },
14795     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
14796     { WM_CTLCOLORLISTBOX, sent|parent },
14797     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
14798     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
14799 
14800     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
14801     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
14802 
14803     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
14804     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
14805     { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
14806     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
14807     { 0 }
14808 };
14809 static const struct message wm_lb_deletestring[] =
14810 {
14811     { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
14812     { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
14813     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
14814     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
14815     { 0 }
14816 };
14817 static const struct message wm_lb_deletestring_reset[] =
14818 {
14819     { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
14820     { LB_RESETCONTENT, sent|wparam|lparam|defwinproc|optional, 0, 0 },
14821     { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
14822     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
14823     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
14824     { 0 }
14825 };
14826 static const struct message wm_lb_addstring[] =
14827 {
14828     { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef },
14829     { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed },
14830     { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee },
14831     { 0 }
14832 };
14833 static const struct message wm_lb_addstring_ownerdraw[] =
14834 {
14835     { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed },
14836     { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf0f2, 0xf30604ed },
14837     { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee },
14838     { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf1f2, 0xf30604ee },
14839     { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef },
14840     { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf2f2, 0xf30604ef },
14841     { 0 }
14842 };
14843 static const struct message wm_lb_addstring_sort_ownerdraw[] =
14844 {
14845     { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed },
14846     { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf0f2, 0xf30604ed },
14847     { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee },
14848     { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ed, 0xf30604ee },
14849     { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf1f2, 0xf30604ee },
14850     { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef },
14851     { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ed, 0xf30604ef },
14852     { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ee, 0xf30604ef },
14853     { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf2f2, 0xf30604ef },
14854     { 0 }
14855 };
14856 
14857 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
14858 
14859 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
14860 
14861 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
14862 {
14863     static LONG defwndproc_counter = 0;
14864     LRESULT ret;
14865     struct recvd_message msg;
14866 
14867     /* do not log painting messages */
14868     if (message != WM_PAINT &&
14869         message != WM_NCPAINT &&
14870         message != WM_SYNCPAINT &&
14871         message != WM_ERASEBKGND &&
14872         message != WM_NCHITTEST &&
14873         message != WM_GETTEXT &&
14874         !ignore_message( message ))
14875     {
14876         msg.hwnd = hwnd;
14877         msg.message = message;
14878         msg.flags = sent|wparam|lparam;
14879         if (defwndproc_counter) msg.flags |= defwinproc;
14880         msg.wParam = wp;
14881         if (message == LB_ADDSTRING)
14882             msg.lParam = lp ? hash_Ly((const char *)lp) : 0;
14883         else
14884             msg.lParam = lp;
14885         msg.descr = "listbox";
14886         add_message(&msg);
14887     }
14888 
14889     defwndproc_counter++;
14890     ret = CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
14891     defwndproc_counter--;
14892 
14893     return ret;
14894 }
14895 
14896 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
14897                                int caret_index, int top_index, int line)
14898 {
14899     LRESULT ret;
14900 
14901     /* calling an orig proc helps to avoid unnecessary message logging */
14902     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
14903     ok_(__FILE__, line)(ret == count, "expected count %d, got %ld\n", count, ret);
14904     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
14905     ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret);
14906     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
14907     ok_(__FILE__, line)(ret == caret_index ||
14908                         broken(cur_sel == -1 && caret_index == 0 && ret == -1),  /* nt4 */
14909                         "expected caret index %d, got %ld\n", caret_index, ret);
14910     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
14911     ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret);
14912 }
14913 
14914 static void test_listbox_messages(void)
14915 {
14916     HWND parent, listbox;
14917     LRESULT ret;
14918 
14919     parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW  | WS_VISIBLE,
14920                              100, 100, 200, 200, 0, 0, 0, NULL);
14921     /* with LBS_HASSTRINGS */
14922     listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
14923                               WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
14924                               10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
14925     listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
14926 
14927     check_lb_state(listbox, 0, LB_ERR, 0, 0);
14928 
14929     flush_sequence();
14930 
14931     log_all_parent_messages++;
14932 
14933     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
14934     ok(ret == 0, "expected 0, got %ld\n", ret);
14935     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
14936     ok(ret == 1, "expected 1, got %ld\n", ret);
14937     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
14938     ok(ret == 2, "expected 2, got %ld\n", ret);
14939 
14940     ok_sequence(wm_lb_addstring_ownerdraw, "LB_ADDSTRING", FALSE);
14941     check_lb_state(listbox, 3, LB_ERR, 0, 0);
14942 
14943     flush_sequence();
14944 
14945     trace("selecting item 0\n");
14946     ret = SendMessageA(listbox, LB_SETCURSEL, 0, 0);
14947     ok(ret == 0, "expected 0, got %ld\n", ret);
14948     ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
14949     check_lb_state(listbox, 3, 0, 0, 0);
14950     flush_sequence();
14951 
14952     trace("selecting item 1\n");
14953     ret = SendMessageA(listbox, LB_SETCURSEL, 1, 0);
14954     ok(ret == 1, "expected 1, got %ld\n", ret);
14955     ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
14956     check_lb_state(listbox, 3, 1, 1, 0);
14957 
14958     trace("selecting item 2\n");
14959     ret = SendMessageA(listbox, LB_SETCURSEL, 2, 0);
14960     ok(ret == 2, "expected 2, got %ld\n", ret);
14961     ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
14962     check_lb_state(listbox, 3, 2, 2, 0);
14963 
14964     trace("clicking on item 0\n");
14965     ret = SendMessageA(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
14966     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
14967     ret = SendMessageA(listbox, WM_LBUTTONUP, 0, 0);
14968     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
14969     ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
14970     check_lb_state(listbox, 3, 0, 0, 0);
14971     flush_sequence();
14972 
14973     trace("deleting item 0\n");
14974     ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14975     ok(ret == 2, "expected 2, got %ld\n", ret);
14976     ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
14977     check_lb_state(listbox, 2, -1, 0, 0);
14978     flush_sequence();
14979 
14980     trace("deleting item 0\n");
14981     ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14982     ok(ret == 1, "expected 1, got %ld\n", ret);
14983     ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
14984     check_lb_state(listbox, 1, -1, 0, 0);
14985     flush_sequence();
14986 
14987     trace("deleting item 0\n");
14988     ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14989     ok(ret == 0, "expected 0, got %ld\n", ret);
14990     ok_sequence(wm_lb_deletestring_reset, "LB_DELETESTRING 0", FALSE );
14991     check_lb_state(listbox, 0, -1, 0, 0);
14992     flush_sequence();
14993 
14994     trace("deleting item 0\n");
14995     ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14996     ok(ret == LB_ERR, "expected LB_ERR, got %ld\n", ret);
14997     check_lb_state(listbox, 0, -1, 0, 0);
14998     flush_sequence();
14999 
15000     log_all_parent_messages--;
15001 
15002     DestroyWindow(listbox);
15003 
15004     /* with LBS_SORT and without LBS_HASSTRINGS */
15005     listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
15006                               WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_SORT | WS_VISIBLE,
15007                               10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
15008     listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
15009 
15010     check_lb_state(listbox, 0, LB_ERR, 0, 0);
15011 
15012     flush_sequence();
15013 
15014     log_all_parent_messages++;
15015 
15016     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
15017     ok(ret == 0, "expected 0, got %ld\n", ret);
15018     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
15019     ok(ret == 1, "expected 1, got %ld\n", ret);
15020     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
15021     ok(ret == 2, "expected 2, got %ld\n", ret);
15022 
15023     ok_sequence(wm_lb_addstring_sort_ownerdraw, "LB_ADDSTRING", FALSE);
15024     check_lb_state(listbox, 3, LB_ERR, 0, 0);
15025 
15026     log_all_parent_messages--;
15027 
15028     DestroyWindow(listbox);
15029 
15030     /* with LBS_HASSTRINGS */
15031     listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
15032                               WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | WS_VISIBLE,
15033                               10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
15034     listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
15035 
15036     check_lb_state(listbox, 0, LB_ERR, 0, 0);
15037 
15038     flush_sequence();
15039 
15040     log_all_parent_messages++;
15041 
15042     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
15043     ok(ret == 0, "expected 0, got %ld\n", ret);
15044     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
15045     ok(ret == 1, "expected 1, got %ld\n", ret);
15046     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
15047     ok(ret == 2, "expected 2, got %ld\n", ret);
15048 
15049     ok_sequence(wm_lb_addstring, "LB_ADDSTRING", FALSE);
15050     check_lb_state(listbox, 3, LB_ERR, 0, 0);
15051 
15052     log_all_parent_messages--;
15053 
15054     DestroyWindow(listbox);
15055 
15056     /* with LBS_HASSTRINGS and LBS_SORT */
15057     listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
15058                               WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | LBS_SORT | WS_VISIBLE,
15059                               10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
15060     listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
15061 
15062     check_lb_state(listbox, 0, LB_ERR, 0, 0);
15063 
15064     flush_sequence();
15065 
15066     log_all_parent_messages++;
15067 
15068     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
15069     ok(ret == 0, "expected 0, got %ld\n", ret);
15070     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
15071     ok(ret == 0, "expected 0, got %ld\n", ret);
15072     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
15073     ok(ret == 1, "expected 1, got %ld\n", ret);
15074 
15075     ok_sequence(wm_lb_addstring, "LB_ADDSTRING", FALSE);
15076     check_lb_state(listbox, 3, LB_ERR, 0, 0);
15077 
15078     log_all_parent_messages--;
15079 
15080     DestroyWindow(listbox);
15081     DestroyWindow(parent);
15082 }
15083 
15084 /*************************** Menu test ******************************/
15085 static const struct message wm_popup_menu_1[] =
15086 {
15087     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
15088     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
15089     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0x20000001 },
15090     { WM_SYSKEYDOWN, sent|wparam|lparam, 'E', 0x20000001 },
15091     { WM_SYSCHAR, sent|wparam|lparam, 'e', 0x20000001 },
15092     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'e' },
15093     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
15094     { WM_INITMENU, sent|lparam, 0, 0 },
15095     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) },
15096     { WM_INITMENUPOPUP, sent|lparam, 0, 1 },
15097     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */
15098     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) },
15099     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 },
15100     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
15101     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001, 0, 0x40000000 },
15102     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */
15103     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
15104     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
15105     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
15106     { WM_MENUCOMMAND, sent }, /* |wparam, 200 - Win9x */
15107     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
15108     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
15109     { 0 }
15110 };
15111 static const struct message wm_popup_menu_2[] =
15112 {
15113     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
15114     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
15115     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
15116     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
15117     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
15118     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
15119     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
15120     { WM_INITMENU, sent|lparam, 0, 0 },
15121     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
15122     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
15123     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
15124     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
15125     { HCBT_CREATEWND, hook },
15126     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
15127                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
15128     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
15129     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
15130     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
15131     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
15132     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
15133     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
15134     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
15135     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
15136     { HCBT_DESTROYWND, hook },
15137     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
15138     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
15139     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
15140     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
15141     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
15142     { WM_MENUCOMMAND, sent }, /* |wparam, 100 - Win9x */
15143     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
15144     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
15145     { 0 }
15146 };
15147 static const struct message wm_popup_menu_3[] =
15148 {
15149     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
15150     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
15151     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
15152     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
15153     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
15154     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
15155     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
15156     { WM_INITMENU, sent|lparam, 0, 0 },
15157     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
15158     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
15159     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
15160     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
15161     { HCBT_CREATEWND, hook },
15162     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
15163                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
15164     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
15165     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
15166     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
15167     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
15168     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
15169     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
15170     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
15171     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
15172     { HCBT_DESTROYWND, hook },
15173     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
15174     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
15175     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
15176     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
15177     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
15178     { WM_COMMAND, sent|wparam|lparam, 100, 0 },
15179     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
15180     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
15181     { 0 }
15182 };
15183 
15184 static const struct message wm_single_menu_item[] =
15185 {
15186     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
15187     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
15188     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0x20000001 },
15189     { WM_SYSKEYDOWN, sent|wparam|lparam, 'Q', 0x20000001 },
15190     { WM_SYSCHAR, sent|wparam|lparam, 'q', 0x20000001 },
15191     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'q' },
15192     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
15193     { WM_INITMENU, sent|lparam, 0, 0 },
15194     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(300,MF_HILITE) },
15195     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
15196     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
15197     { WM_MENUCOMMAND, sent },
15198     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0xe0000001 },
15199     { WM_SYSKEYUP, sent|wparam|lparam, 'Q', 0xe0000001 },
15200     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 },
15201     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
15202 
15203     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 1 },
15204     { WM_KEYDOWN, sent|wparam|lparam, VK_ESCAPE, 1 },
15205     { WM_CHAR,  sent|wparam|lparam, VK_ESCAPE, 0x00000001 },
15206     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 },
15207     { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
15208     { 0 }
15209 };
15210 
15211 static LRESULT WINAPI parent_menu_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
15212 {
15213     if (message == WM_ENTERIDLE ||
15214         message == WM_INITMENU ||
15215         message == WM_INITMENUPOPUP ||
15216         message == WM_MENUSELECT ||
15217         message == WM_PARENTNOTIFY ||
15218         message == WM_ENTERMENULOOP ||
15219         message == WM_EXITMENULOOP ||
15220         message == WM_UNINITMENUPOPUP ||
15221         message == WM_KEYDOWN ||
15222         message == WM_KEYUP ||
15223         message == WM_CHAR ||
15224         message == WM_SYSKEYDOWN ||
15225         message == WM_SYSKEYUP ||
15226         message == WM_SYSCHAR ||
15227         message == WM_COMMAND ||
15228         message == WM_MENUCOMMAND)
15229     {
15230         struct recvd_message msg;
15231 
15232         msg.hwnd = hwnd;
15233         msg.message = message;
15234         msg.flags = sent|wparam|lparam;
15235         msg.wParam = wp;
15236         msg.lParam = lp;
15237         msg.descr = "parent_menu_proc";
15238         add_message(&msg);
15239     }
15240 
15241     return DefWindowProcA(hwnd, message, wp, lp);
15242 }
15243 
15244 static void set_menu_style(HMENU hmenu, DWORD style)
15245 {
15246     MENUINFO mi;
15247     BOOL ret;
15248 
15249     mi.cbSize = sizeof(mi);
15250     mi.fMask = MIM_STYLE;
15251     mi.dwStyle = style;
15252     SetLastError(0xdeadbeef);
15253     ret = pSetMenuInfo(hmenu, &mi);
15254     ok(ret, "SetMenuInfo error %u\n", GetLastError());
15255 }
15256 
15257 static DWORD get_menu_style(HMENU hmenu)
15258 {
15259     MENUINFO mi;
15260     BOOL ret;
15261 
15262     mi.cbSize = sizeof(mi);
15263     mi.fMask = MIM_STYLE;
15264     mi.dwStyle = 0;
15265     SetLastError(0xdeadbeef);
15266     ret = pGetMenuInfo(hmenu, &mi);
15267     ok(ret, "GetMenuInfo error %u\n", GetLastError());
15268 
15269     return mi.dwStyle;
15270 }
15271 
15272 static void test_menu_messages(void)
15273 {
15274     MSG msg;
15275     WNDCLASSA cls;
15276     HMENU hmenu, hmenu_popup;
15277     HWND hwnd;
15278     DWORD style;
15279 
15280     if (!pGetMenuInfo || !pSetMenuInfo)
15281     {
15282         win_skip("GetMenuInfo and/or SetMenuInfo are not available\n");
15283         return;
15284     }
15285     cls.style = 0;
15286     cls.lpfnWndProc = parent_menu_proc;
15287     cls.cbClsExtra = 0;
15288     cls.cbWndExtra = 0;
15289     cls.hInstance = GetModuleHandleA(0);
15290     cls.hIcon = 0;
15291     cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
15292     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
15293     cls.lpszMenuName = NULL;
15294     cls.lpszClassName = "TestMenuClass";
15295     UnregisterClassA(cls.lpszClassName, cls.hInstance);
15296     if (!RegisterClassA(&cls)) assert(0);
15297 
15298     SetLastError(0xdeadbeef);
15299     hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
15300                            100, 100, 200, 200, 0, 0, 0, NULL);
15301     ok(hwnd != 0, "LoadMenuA error %u\n", GetLastError());
15302 
15303     SetLastError(0xdeadbeef);
15304     hmenu = LoadMenuA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
15305     ok(hmenu != 0, "LoadMenuA error %u\n", GetLastError());
15306 
15307     SetMenu(hwnd, hmenu);
15308     SetForegroundWindow( hwnd );
15309     flush_events();
15310 
15311     set_menu_style(hmenu, MNS_NOTIFYBYPOS);
15312     style = get_menu_style(hmenu);
15313     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
15314 
15315     hmenu_popup = GetSubMenu(hmenu, 0);
15316     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
15317     style = get_menu_style(hmenu_popup);
15318     ok(style == 0, "expected 0, got %u\n", style);
15319 
15320     hmenu_popup = GetSubMenu(hmenu_popup, 0);
15321     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
15322     style = get_menu_style(hmenu_popup);
15323     ok(style == 0, "expected 0, got %u\n", style);
15324 
15325     /* Alt+E, Enter */
15326     trace("testing a popup menu command\n");
15327     flush_sequence();
15328     keybd_event(VK_MENU, 0, 0, 0);
15329     keybd_event('E', 0, 0, 0);
15330     keybd_event('E', 0, KEYEVENTF_KEYUP, 0);
15331     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
15332     keybd_event(VK_RETURN, 0, 0, 0);
15333     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
15334     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15335     {
15336         TranslateMessage(&msg);
15337         DispatchMessageA(&msg);
15338     }
15339     if (!sequence_cnt)  /* we didn't get any message */
15340     {
15341         skip( "queuing key events not supported\n" );
15342         goto done;
15343     }
15344     /* win98 queues only a WM_KEYUP and doesn't start menu tracking */
15345     if (sequence[0].message == WM_KEYUP && sequence[0].wParam == VK_MENU)
15346     {
15347         win_skip( "menu tracking through VK_MENU not supported\n" );
15348         goto done;
15349     }
15350     ok_sequence(wm_popup_menu_1, "popup menu command", FALSE);
15351 
15352     /* Alt+F, Right, Enter */
15353     trace("testing submenu of a popup menu command\n");
15354     flush_sequence();
15355     keybd_event(VK_MENU, 0, 0, 0);
15356     keybd_event('F', 0, 0, 0);
15357     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
15358     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
15359     keybd_event(VK_RIGHT, 0, 0, 0);
15360     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
15361     keybd_event(VK_RETURN, 0, 0, 0);
15362     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
15363     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15364     {
15365         TranslateMessage(&msg);
15366         DispatchMessageA(&msg);
15367     }
15368     ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE);
15369 
15370     trace("testing single menu item command\n");
15371     flush_sequence();
15372     keybd_event(VK_MENU, 0, 0, 0);
15373     keybd_event('Q', 0, 0, 0);
15374     keybd_event('Q', 0, KEYEVENTF_KEYUP, 0);
15375     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
15376     keybd_event(VK_ESCAPE, 0, 0, 0);
15377     keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
15378     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15379     {
15380         TranslateMessage(&msg);
15381         DispatchMessageA(&msg);
15382     }
15383     ok_sequence(wm_single_menu_item, "single menu item command", FALSE);
15384 
15385     set_menu_style(hmenu, 0);
15386     style = get_menu_style(hmenu);
15387     ok(style == 0, "expected 0, got %u\n", style);
15388 
15389     hmenu_popup = GetSubMenu(hmenu, 0);
15390     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
15391     set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS);
15392     style = get_menu_style(hmenu_popup);
15393     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
15394 
15395     hmenu_popup = GetSubMenu(hmenu_popup, 0);
15396     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
15397     style = get_menu_style(hmenu_popup);
15398     ok(style == 0, "expected 0, got %u\n", style);
15399 
15400     /* Alt+F, Right, Enter */
15401     trace("testing submenu of a popup menu command\n");
15402     flush_sequence();
15403     keybd_event(VK_MENU, 0, 0, 0);
15404     keybd_event('F', 0, 0, 0);
15405     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
15406     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
15407     keybd_event(VK_RIGHT, 0, 0, 0);
15408     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
15409     keybd_event(VK_RETURN, 0, 0, 0);
15410     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
15411     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15412     {
15413         TranslateMessage(&msg);
15414         DispatchMessageA(&msg);
15415     }
15416     ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE);
15417 
15418 done:
15419     DestroyWindow(hwnd);
15420     DestroyMenu(hmenu);
15421 }
15422 
15423 
15424 static void test_paintingloop(void)
15425 {
15426     HWND hwnd;
15427 
15428     paint_loop_done = FALSE;
15429     hwnd = CreateWindowExA(0x0,"PaintLoopWindowClass",
15430                                "PaintLoopWindowClass",WS_OVERLAPPEDWINDOW,
15431                                 100, 100, 100, 100, 0, 0, 0, NULL );
15432     ok(hwnd != 0, "PaintLoop window error %u\n", GetLastError());
15433     ShowWindow(hwnd,SW_NORMAL);
15434     SetFocus(hwnd);
15435 
15436     while (!paint_loop_done)
15437     {
15438         MSG msg;
15439         if (PeekMessageA(&msg, 0, 0, 0, 1))
15440         {
15441             TranslateMessage(&msg);
15442             DispatchMessageA(&msg);
15443         }
15444     }
15445     DestroyWindow(hwnd);
15446 }
15447 
15448 static const struct message NCRBUTTONDOWNSeq[] =
15449 {
15450     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
15451     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
15452     { WM_CAPTURECHANGED, sent },
15453     { WM_CONTEXTMENU, sent, /*hwnd*/0, -1 },
15454     { 0 }
15455 };
15456 
15457 static const struct message NCXBUTTONUPSeq1[] =
15458 {
15459     { WM_APPCOMMAND, sent|lparam, /*hwnd*/0, MAKELPARAM(0, FAPPCOMMAND_MOUSE | APPCOMMAND_BROWSER_BACKWARD) },
15460     { 0 }
15461 };
15462 
15463 static const struct message NCXBUTTONUPSeq2[] =
15464 {
15465     { WM_APPCOMMAND, sent|lparam, /*hwnd*/0, MAKELPARAM(0, FAPPCOMMAND_MOUSE | APPCOMMAND_BROWSER_FORWARD) },
15466     { 0 }
15467 };
15468 
15469 /* DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0) to minimized visible window */
15470 static const struct message WmRestoreMinimizedOverlappedSeq[] =
15471 {
15472     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_RESTORE, 0 },
15473     { HCBT_MINMAX, hook },
15474     { WM_QUERYOPEN, sent },
15475     { WM_GETTEXT, sent|optional },
15476     { WM_NCACTIVATE, sent|optional },
15477     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
15478     { WM_WINDOWPOSCHANGED, sent|optional },
15479     { WM_WINDOWPOSCHANGING, sent|optional },
15480     { WM_GETMINMAXINFO, sent|defwinproc },
15481     { WM_NCCALCSIZE, sent|optional },
15482     { WM_NCPAINT, sent|optional },
15483     { WM_GETTEXT, sent|defwinproc|optional },
15484     { WM_ERASEBKGND, sent|optional },
15485     { WM_WINDOWPOSCHANGED, sent|optional },
15486     { HCBT_ACTIVATE, hook },
15487     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
15488     { WM_ACTIVATEAPP, sent|wparam, TRUE },
15489     { WM_NCACTIVATE, sent|wparam, TRUE },
15490     { WM_GETTEXT, sent|defwinproc|optional },
15491     { WM_ACTIVATE, sent|wparam, TRUE },
15492     { HCBT_SETFOCUS, hook },
15493     { WM_SETFOCUS, sent|defwinproc },
15494     { WM_NCPAINT, sent },
15495     { WM_GETTEXT, sent|defwinproc|optional },
15496     { WM_ERASEBKGND, sent },
15497     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_FRAMECHANGED|SWP_STATECHANGED },
15498     { WM_MOVE, sent|defwinproc },
15499     { WM_SIZE, sent|defwinproc },
15500     { WM_NCCALCSIZE, sent|optional },
15501     { WM_NCPAINT, sent|optional },
15502     { WM_ERASEBKGND, sent|optional },
15503     { WM_ACTIVATE, sent|wparam, TRUE },
15504     { WM_SYNCPAINT, sent|optional },
15505     { WM_PAINT, sent },
15506     { 0 }
15507 };
15508 
15509 struct rbuttonup_thread_data
15510 {
15511     HWND hwnd;
15512     HANDLE wndproc_finished;
15513 };
15514 
15515 static DWORD CALLBACK post_rbuttonup_msg( void *arg )
15516 {
15517     struct rbuttonup_thread_data *data = arg;
15518     DWORD ret;
15519 
15520     ret = WaitForSingleObject( data->wndproc_finished, 500 );
15521     todo_wine ok( ret == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", ret );
15522     if( ret == WAIT_OBJECT_0 ) return 0;
15523 
15524     PostMessageA( data->hwnd, WM_RBUTTONUP, 0, 0 );
15525     return 0;
15526 }
15527 
15528 static void test_defwinproc(void)
15529 {
15530     HWND hwnd;
15531     MSG msg;
15532     BOOL gotwmquit = FALSE;
15533     POINT pos;
15534     RECT rect;
15535     INT x, y;
15536     LRESULT res;
15537     struct rbuttonup_thread_data data;
15538     char buffA[64];
15539     HANDLE thread;
15540 
15541     hwnd = CreateWindowExA(0, "TestWindowClass", "test_defwndproc",
15542             WS_VISIBLE | WS_CAPTION | WS_OVERLAPPEDWINDOW, 0,0,500,100,0,0,0, NULL);
15543     assert(hwnd);
15544     flush_events();
15545 
15546     buffA[0] = 0;
15547     GetWindowTextA(hwnd, buffA, ARRAY_SIZE(buffA));
15548     ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
15549 
15550     /* Zero high word of the lParam */
15551     res = DefWindowProcA(hwnd, WM_SETTEXT, 0, 0x1234);
15552     ok(res == 0, "WM_SETTEXT was expected to fail, %ld\n", res);
15553 
15554     GetWindowTextA(hwnd, buffA, ARRAY_SIZE(buffA));
15555     ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
15556 
15557     res = DefWindowProcW(hwnd, WM_SETTEXT, 0, 0x1234);
15558     ok(res == 0, "WM_SETTEXT was expected to fail, %ld\n", res);
15559 
15560     GetWindowTextA(hwnd, buffA, ARRAY_SIZE(buffA));
15561     ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
15562 
15563     ShowWindow(hwnd, SW_MINIMIZE);
15564     flush_events();
15565     flush_sequence();
15566 
15567     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
15568     flush_events();
15569     ok_sequence(WmRestoreMinimizedOverlappedSeq, "DefWindowProcA(SC_RESTORE):overlapped", TRUE);
15570     flush_sequence();
15571 
15572     GetCursorPos(&pos);
15573     GetWindowRect(hwnd, &rect);
15574     x = (rect.left+rect.right) / 2;
15575     y = rect.top + GetSystemMetrics(SM_CYFRAME) + 1;
15576     SetCursorPos(x, y);
15577     flush_events();
15578     res = DefWindowProcA( hwnd, WM_NCHITTEST, 0, MAKELPARAM(x, y));
15579     ok(res == HTCAPTION, "WM_NCHITTEST returned %ld\n", res);
15580 
15581     mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 );
15582     mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 );
15583     flush_events();
15584 
15585     flush_sequence();
15586     mouse_event( MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0 );
15587     /* workaround for missing support for clicking on window frame */
15588     data.hwnd = hwnd;
15589     data.wndproc_finished = CreateEventA( NULL, FALSE, FALSE, NULL );
15590     thread = CreateThread( NULL, 0, post_rbuttonup_msg, (void*)&data, 0, NULL );
15591 
15592     DefWindowProcA( hwnd, WM_NCRBUTTONDOWN, HTCAPTION, MAKELPARAM(x, y));
15593     ok_sequence(NCRBUTTONDOWNSeq, "WM_NCRBUTTONDOWN on caption", FALSE);
15594 
15595     res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, 0, MAKELPARAM(x, y));
15596     ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15597     ok_sequence(WmEmptySeq, "WM_NCXBUTTONUP without button", FALSE);
15598 
15599     res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, XBUTTON1), MAKELPARAM(x, y));
15600     ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15601     ok_sequence(NCXBUTTONUPSeq1, "WM_NCXBUTTONUP with XBUTTON1", FALSE);
15602 
15603     res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, XBUTTON2), MAKELPARAM(x, y));
15604     ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15605     ok_sequence(NCXBUTTONUPSeq2, "WM_NCXBUTTONUP with XBUTTON2", FALSE);
15606 
15607     res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, 3), MAKELPARAM(x, y));
15608     ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15609     ok_sequence(WmEmptySeq, "WM_NCXBUTTONUP with invalid button", FALSE);
15610 
15611     SetEvent( data.wndproc_finished );
15612     WaitForSingleObject( thread, 1000 );
15613     CloseHandle( data.wndproc_finished );
15614     CloseHandle( thread );
15615 
15616     SetCursorPos(pos.x, pos.y);
15617 
15618     DefWindowProcA( hwnd, WM_ENDSESSION, 1, 0);
15619     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) {
15620         if( msg.message == WM_QUIT) gotwmquit = TRUE;
15621         DispatchMessageA( &msg );
15622     }
15623     ok(!gotwmquit, "Unexpected WM_QUIT message!\n");
15624     DestroyWindow( hwnd);
15625 }
15626 
15627 static void test_desktop_winproc(void)
15628 {
15629     HINSTANCE instance = GetModuleHandleA(NULL);
15630     RECT rect, default_rect;
15631     WNDPROC desktop_proc;
15632     char buffer[256];
15633     WNDCLASSA cls;
15634     LRESULT res;
15635     HWND hwnd;
15636     BOOL ret;
15637 
15638     ret = GetClassInfoA(instance, (const CHAR *)MAKEINTATOM(32769), &cls);
15639     ok(ret, "Failed to get desktop class.\n");
15640     desktop_proc = cls.lpfnWndProc;
15641 
15642     memset(&cls, 0, sizeof(cls));
15643     cls.lpfnWndProc = desktop_proc;
15644     cls.hInstance = instance;
15645     cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
15646     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
15647     cls.lpszClassName = "TestDesktopClass";
15648     ret = !!RegisterClassA(&cls);
15649     ok(ret, "Failed to register class.\n");
15650 
15651     hwnd = CreateWindowExA(0, cls.lpszClassName, "test_desktop_wndproc",
15652             WS_VISIBLE | WS_CAPTION | WS_OVERLAPPEDWINDOW, 0, 0, 500, 100, 0, 0, 0, NULL);
15653     if (!hwnd) /* win2003 */
15654     {
15655         skip("Failed to create window with desktop window procedure.\n");
15656         goto out_unregister;
15657     }
15658 
15659     memset(&cls, 0, sizeof(cls));
15660     ret = GetClassInfoA(instance, "TestDesktopClass", &cls);
15661     ok(ret, "Failed to get class info.\n");
15662     ok(cls.lpfnWndProc == desktop_proc, "Got %p, expected %p.\n", cls.lpfnWndProc, desktop_proc);
15663 
15664     GetWindowTextA(hwnd, buffer, ARRAY_SIZE(buffer));
15665     todo_wine ok(!strcmp(buffer, "test_desktop_wndproc"), "Got unexpected window text: %s.\n", buffer);
15666 
15667     res = CallWindowProcA(desktop_proc, hwnd, WM_SETTEXT, 0, (LPARAM)"test");
15668     ok(res == TRUE, "Failed to set text, %ld.\n", res);
15669     GetWindowTextA(hwnd, buffer, ARRAY_SIZE(buffer));
15670     ok(!strcmp(buffer, "test"), "Got unexpected window text: %s.\n", buffer);
15671 
15672     SetRect(&default_rect, 0, 0, 100, 100);
15673     res = DefWindowProcW(hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&default_rect);
15674     ok(!res, "Got unexpected result %ld.\n", res);
15675 
15676     SetRect(&rect, 0, 0, 100, 100);
15677     res = CallWindowProcA(desktop_proc, hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rect);
15678     ok(!res, "Got unexpected result %ld.\n", res);
15679     todo_wine ok(EqualRect(&rect, &default_rect), "rect Got %s, expected %s.\n",
15680             wine_dbgstr_rect(&rect), wine_dbgstr_rect(&default_rect));
15681 
15682     DestroyWindow(hwnd);
15683 
15684 out_unregister:
15685     UnregisterClassA("TestDesktopClass", instance);
15686 }
15687 
15688 #define clear_clipboard(hwnd)  clear_clipboard_(__LINE__, (hwnd))
15689 static void clear_clipboard_(int line, HWND hWnd)
15690 {
15691     BOOL succ;
15692     succ = OpenClipboard(hWnd);
15693     ok_(__FILE__, line)(succ, "OpenClipboard failed, err=%u\n", GetLastError());
15694     succ = EmptyClipboard();
15695     ok_(__FILE__, line)(succ, "EmptyClipboard failed, err=%u\n", GetLastError());
15696     succ = CloseClipboard();
15697     ok_(__FILE__, line)(succ, "CloseClipboard failed, err=%u\n", GetLastError());
15698 }
15699 
15700 #define expect_HWND(expected, got) expect_HWND_(__LINE__, (expected), (got))
15701 static void expect_HWND_(int line, HWND expected, HWND got)
15702 {
15703     ok_(__FILE__, line)(got==expected, "Expected %p, got %p\n", expected, got);
15704 }
15705 
15706 static WNDPROC pOldViewerProc;
15707 
15708 static LRESULT CALLBACK recursive_viewer_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
15709 {
15710     static BOOL recursion_guard;
15711 
15712     if (message == WM_DRAWCLIPBOARD && !recursion_guard)
15713     {
15714         recursion_guard = TRUE;
15715         clear_clipboard(hWnd);
15716         recursion_guard = FALSE;
15717     }
15718     return CallWindowProcA(pOldViewerProc, hWnd, message, wParam, lParam);
15719 }
15720 
15721 static void test_clipboard_viewers(void)
15722 {
15723     static struct message wm_change_cb_chain[] =
15724     {
15725         { WM_CHANGECBCHAIN, sent|wparam|lparam, 0, 0 },
15726         { 0 }
15727     };
15728     static const struct message wm_clipboard_destroyed[] =
15729     {
15730         { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
15731         { 0 }
15732     };
15733     static struct message wm_clipboard_changed[] =
15734     {
15735         { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
15736         { 0 }
15737     };
15738     static struct message wm_clipboard_changed_and_owned[] =
15739     {
15740         { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
15741         { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
15742         { 0 }
15743     };
15744 
15745     HINSTANCE hInst = GetModuleHandleA(NULL);
15746     HWND hWnd1, hWnd2, hWnd3;
15747     HWND hOrigViewer;
15748     HWND hRet;
15749 
15750     hWnd1 = CreateWindowExA(0, "TestWindowClass", "Clipboard viewer test wnd 1",
15751         WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
15752         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
15753         GetDesktopWindow(), NULL, hInst, NULL);
15754     hWnd2 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 2",
15755         WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
15756         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
15757         GetDesktopWindow(), NULL, hInst, NULL);
15758     hWnd3 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 3",
15759         WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
15760         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
15761         GetDesktopWindow(), NULL, hInst, NULL);
15762     trace("clipbd viewers: hWnd1=%p, hWnd2=%p, hWnd3=%p\n", hWnd1, hWnd2, hWnd3);
15763     assert(hWnd1 && hWnd2 && hWnd3);
15764 
15765     CountClipboardFormats(); /* Ensure that we do not have an X11 update to the clipboard */
15766     flush_sequence();
15767 
15768     /* Test getting the clipboard viewer and setting the viewer to NULL. */
15769     hOrigViewer = GetClipboardViewer();
15770     hRet = SetClipboardViewer(NULL);
15771     ok_sequence(WmEmptySeq, "set viewer to NULL", FALSE);
15772     expect_HWND(hOrigViewer, hRet);
15773     expect_HWND(NULL, GetClipboardViewer());
15774 
15775     /* Test registering hWnd1 as a viewer. */
15776     hRet = SetClipboardViewer(hWnd1);
15777     wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
15778     ok_sequence(wm_clipboard_changed, "set viewer NULL->1", FALSE);
15779     expect_HWND(NULL, hRet);
15780     expect_HWND(hWnd1, GetClipboardViewer());
15781 
15782     /* Test that changing the clipboard actually refreshes the registered viewer. */
15783     clear_clipboard(hWnd1);
15784     wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
15785     ok_sequence(wm_clipboard_changed, "clear clipbd (viewer=owner=1)", FALSE);
15786 
15787     /* Again, but with different owner. */
15788     clear_clipboard(hWnd2);
15789     wm_clipboard_changed_and_owned[1].wParam = (WPARAM) GetClipboardOwner();
15790     ok_sequence(wm_clipboard_changed_and_owned, "clear clipbd (viewer=1, owner=2)", FALSE);
15791 
15792     /* Test re-registering same window. */
15793     hRet = SetClipboardViewer(hWnd1);
15794     wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
15795     ok_sequence(wm_clipboard_changed, "set viewer 1->1", FALSE);
15796     expect_HWND(hWnd1, hRet);
15797     expect_HWND(hWnd1, GetClipboardViewer());
15798 
15799     /* Test ChangeClipboardChain. */
15800     ChangeClipboardChain(hWnd2, hWnd3);
15801     wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
15802     wm_change_cb_chain[0].lParam = (LPARAM) hWnd3;
15803     ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=3)", FALSE);
15804     expect_HWND(hWnd1, GetClipboardViewer());
15805 
15806     ChangeClipboardChain(hWnd2, NULL);
15807     wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
15808     wm_change_cb_chain[0].lParam = 0;
15809     ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=NULL)", FALSE);
15810     expect_HWND(hWnd1, GetClipboardViewer());
15811 
15812     ChangeClipboardChain(NULL, hWnd2);
15813     ok_sequence(WmEmptySeq, "change chain (viewer=1, remove=NULL, next=2)", FALSE);
15814     expect_HWND(hWnd1, GetClipboardViewer());
15815 
15816     /* Actually change clipboard viewer with ChangeClipboardChain. */
15817     ChangeClipboardChain(hWnd1, hWnd2);
15818     ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=2)", FALSE);
15819     expect_HWND(hWnd2, GetClipboardViewer());
15820 
15821     /* Test that no refresh messages are sent when viewer has unregistered. */
15822     clear_clipboard(hWnd2);
15823     ok_sequence(WmEmptySeq, "clear clipd (viewer=2, owner=1)", FALSE);
15824 
15825     /* Register hWnd1 again. */
15826     ChangeClipboardChain(hWnd2, hWnd1);
15827     ok_sequence(WmEmptySeq, "change chain (viewer=remove=2, next=1)", FALSE);
15828     expect_HWND(hWnd1, GetClipboardViewer());
15829 
15830     /* Subclass hWnd1 so that when it receives a WM_DRAWCLIPBOARD message, it
15831      * changes the clipboard. When this happens, the system shouldn't send
15832      * another WM_DRAWCLIPBOARD (as this could cause an infinite loop).
15833      */
15834     pOldViewerProc = (WNDPROC) SetWindowLongPtrA(hWnd1, GWLP_WNDPROC, (LONG_PTR) recursive_viewer_proc);
15835     clear_clipboard(hWnd2);
15836     /* The clipboard owner is changed in recursive_viewer_proc: */
15837     wm_clipboard_changed[0].wParam = (WPARAM) hWnd2;
15838     ok_sequence(wm_clipboard_changed, "recursive clear clipbd (viewer=1, owner=2)", TRUE);
15839 
15840     /* Test unregistering. */
15841     ChangeClipboardChain(hWnd1, NULL);
15842     ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=NULL)", FALSE);
15843     expect_HWND(NULL, GetClipboardViewer());
15844 
15845     clear_clipboard(hWnd1);
15846     ok_sequence(wm_clipboard_destroyed, "clear clipbd (no viewer, owner=1)", FALSE);
15847 
15848     DestroyWindow(hWnd1);
15849     DestroyWindow(hWnd2);
15850     DestroyWindow(hWnd3);
15851     SetClipboardViewer(hOrigViewer);
15852 }
15853 
15854 static void test_PostMessage(void)
15855 {
15856     static const struct
15857     {
15858         HWND hwnd;
15859         BOOL ret;
15860     } data[] =
15861     {
15862         { HWND_TOP /* 0 */, TRUE },
15863         { HWND_BROADCAST, TRUE },
15864         { HWND_BOTTOM, TRUE },
15865         { HWND_TOPMOST, TRUE },
15866         { HWND_NOTOPMOST, FALSE },
15867         { HWND_MESSAGE, FALSE },
15868         { (HWND)0xdeadbeef, FALSE }
15869     };
15870     int i;
15871     HWND hwnd;
15872     BOOL ret;
15873     MSG msg;
15874     static const WCHAR staticW[] = {'s','t','a','t','i','c',0};
15875 
15876     SetLastError(0xdeadbeef);
15877     hwnd = CreateWindowExW(0, staticW, NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
15878     if (!hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
15879     {
15880         win_skip("Skipping some PostMessage tests on Win9x/WinMe\n");
15881         return;
15882     }
15883     assert(hwnd);
15884 
15885     flush_events();
15886 
15887     PostMessageA(hwnd, WM_USER+1, 0x1234, 0x5678);
15888     PostMessageA(0, WM_USER+2, 0x5678, 0x1234);
15889 
15890     for (i = 0; i < ARRAY_SIZE(data); i++)
15891     {
15892         memset(&msg, 0xab, sizeof(msg));
15893         ret = PeekMessageA(&msg, data[i].hwnd, 0, 0, PM_NOREMOVE);
15894         ok(ret == data[i].ret, "%d: hwnd %p expected %d, got %d\n", i, data[i].hwnd, data[i].ret, ret);
15895         if (data[i].ret)
15896         {
15897             if (data[i].hwnd)
15898                 ok(ret && msg.hwnd == 0 && msg.message == WM_USER+2 &&
15899                    msg.wParam == 0x5678 && msg.lParam == 0x1234,
15900                    "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/0/WM_USER+2/0x5678/0x1234\n",
15901                    i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam);
15902             else
15903                 ok(ret && msg.hwnd == hwnd && msg.message == WM_USER+1 &&
15904                    msg.wParam == 0x1234 && msg.lParam == 0x5678,
15905                    "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/%p/WM_USER+1/0x1234/0x5678\n",
15906                    i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam, msg.hwnd);
15907         }
15908     }
15909 
15910     DestroyWindow(hwnd);
15911     flush_events();
15912 }
15913 
15914 static LPARAM g_broadcast_lparam;
15915 static LRESULT WINAPI broadcast_test_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
15916 {
15917     WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
15918 
15919     if (wParam == 0xbaadbeef)
15920         g_broadcast_lparam = wParam;
15921     else
15922         g_broadcast_lparam = 0;
15923 
15924     return CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
15925 }
15926 
15927 static void test_broadcast(void)
15928 {
15929     static const UINT messages[] =
15930     {
15931         WM_USER-1,
15932         WM_USER,
15933         WM_USER+1,
15934         0xc000-1,
15935         0xc000, /* lowest possible atom returned by RegisterWindowMessage */
15936         0xffff,
15937     };
15938     WNDPROC oldproc;
15939     unsigned int i;
15940     HWND hwnd;
15941 
15942     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, NULL);
15943     ok(hwnd != NULL, "got %p\n", hwnd);
15944 
15945     oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)broadcast_test_proc);
15946     SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
15947 
15948     for (i = 0; i < ARRAY_SIZE(messages); i++)
15949     {
15950         BOOL ret;
15951         MSG msg;
15952 
15953         flush_events();
15954         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15955             ;
15956 
15957         /* post, broadcast */
15958         ret = PostMessageA(HWND_BROADCAST, messages[i], 0, 0);
15959         ok(ret, "%d: got %d, error %d\n", i, ret, GetLastError());
15960 
15961         memset(&msg, 0xab, sizeof(msg));
15962         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
15963         if (messages[i] < WM_USER || messages[i] >= 0xc000)
15964         {
15965             ok(ret, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError());
15966             ok(msg.hwnd == hwnd, "%d: got %p\n", i, msg.hwnd);
15967         }
15968         else
15969         {
15970             ok(!ret, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError());
15971         }
15972 
15973         /* post, topmost */
15974         ret = PostMessageA(HWND_TOPMOST, messages[i], 0, 0);
15975         ok(ret, "%d: got %d, error %d\n", i, ret, GetLastError());
15976 
15977         memset(&msg, 0xab, sizeof(msg));
15978         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
15979         if (messages[i] < WM_USER || messages[i] >= 0xc000)
15980         {
15981             ok(ret, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError());
15982             ok(msg.hwnd == hwnd, "%d: got %p\n", i, msg.hwnd);
15983         }
15984         else
15985         {
15986             ok(!ret, "%d: got %d, error %d\n", i, ret, GetLastError());
15987         }
15988 
15989         /* send, broadcast */
15990         g_broadcast_lparam = 0xdead;
15991         ret = SendMessageTimeoutA(HWND_BROADCAST, messages[i], 0xbaadbeef, 0, SMTO_NORMAL, 2000, NULL);
15992         if (!ret && GetLastError() == ERROR_TIMEOUT)
15993             win_skip("broadcasting test %d, timeout\n", i);
15994         else
15995         {
15996             if (messages[i] < WM_USER || messages[i] >= 0xc000)
15997             {
15998                 ok(g_broadcast_lparam == 0xbaadbeef, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
15999                     g_broadcast_lparam, GetLastError());
16000             }
16001             else
16002             {
16003                 ok(g_broadcast_lparam == 0xdead, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
16004                     g_broadcast_lparam, GetLastError());
16005             }
16006         }
16007 
16008         /* send, topmost */
16009         g_broadcast_lparam = 0xdead;
16010         ret = SendMessageTimeoutA(HWND_TOPMOST, messages[i], 0xbaadbeef, 0, SMTO_NORMAL, 2000, NULL);
16011         if (!ret && GetLastError() == ERROR_TIMEOUT)
16012             win_skip("broadcasting test %d, timeout\n", i);
16013         else
16014         {
16015             if (messages[i] < WM_USER || messages[i] >= 0xc000)
16016             {
16017                 ok(g_broadcast_lparam == 0xbaadbeef, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
16018                     g_broadcast_lparam, GetLastError());
16019             }
16020             else
16021             {
16022                 ok(g_broadcast_lparam == 0xdead, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
16023                     g_broadcast_lparam, GetLastError());
16024             }
16025         }
16026     }
16027 
16028     DestroyWindow(hwnd);
16029 }
16030 
16031 static const struct
16032 {
16033     DWORD exp, broken;
16034     BOOL todo;
16035 } wait_idle_expect[] =
16036 {
16037 /* 0 */  { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
16038          { WAIT_TIMEOUT, 0,            FALSE },
16039          { WAIT_TIMEOUT, 0,            FALSE },
16040          { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
16041          { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
16042 /* 5 */  { WAIT_TIMEOUT, 0,            FALSE },
16043          { WAIT_TIMEOUT, 0,            FALSE },
16044          { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
16045          { 0,            0,            FALSE },
16046          { 0,            0,            FALSE },
16047 /* 10 */ { 0,            0,            FALSE },
16048          { 0,            0,            FALSE },
16049          { 0,            WAIT_TIMEOUT, FALSE },
16050          { 0,            0,            FALSE },
16051          { 0,            0,            FALSE },
16052 /* 15 */ { 0,            0,            FALSE },
16053          { WAIT_TIMEOUT, 0,            FALSE },
16054          { WAIT_TIMEOUT, 0,            FALSE },
16055          { WAIT_TIMEOUT, 0,            FALSE },
16056          { WAIT_TIMEOUT, 0,            FALSE },
16057 /* 20 */ { WAIT_TIMEOUT, 0,            FALSE },
16058 };
16059 
16060 static DWORD CALLBACK do_wait_idle_child_thread( void *arg )
16061 {
16062     MSG msg;
16063 
16064     PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
16065     Sleep( 200 );
16066     MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
16067     return 0;
16068 }
16069 
16070 static void do_wait_idle_child( int arg )
16071 {
16072     WNDCLASSA cls;
16073     MSG msg;
16074     HWND hwnd = 0;
16075     HANDLE thread;
16076     DWORD id;
16077     HANDLE start_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_start" );
16078     HANDLE end_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_end" );
16079 
16080     memset( &cls, 0, sizeof(cls) );
16081     cls.lpfnWndProc   = DefWindowProcA;
16082     cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
16083     cls.hCursor       = LoadCursorA(0, (LPCSTR)IDC_ARROW);
16084     cls.lpszClassName = "TestClass";
16085     RegisterClassA( &cls );
16086 
16087     PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );  /* create the msg queue */
16088 
16089     ok( start_event != 0, "failed to create start event, error %u\n", GetLastError() );
16090     ok( end_event != 0, "failed to create end event, error %u\n", GetLastError() );
16091 
16092     switch (arg)
16093     {
16094     case 0:
16095         SetEvent( start_event );
16096         break;
16097     case 1:
16098         SetEvent( start_event );
16099         Sleep( 200 );
16100         PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
16101         break;
16102     case 2:
16103         SetEvent( start_event );
16104         Sleep( 200 );
16105         PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
16106         PostThreadMessageA( GetCurrentThreadId(), WM_COMMAND, 0x1234, 0xabcd );
16107         PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
16108         break;
16109     case 3:
16110         SetEvent( start_event );
16111         Sleep( 200 );
16112         SendMessageA( HWND_BROADCAST, WM_WININICHANGE, 0, 0 );
16113         break;
16114     case 4:
16115         SetEvent( start_event );
16116         Sleep( 200 );
16117         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
16118         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
16119         break;
16120     case 5:
16121         SetEvent( start_event );
16122         Sleep( 200 );
16123         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
16124         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
16125         break;
16126     case 6:
16127         SetEvent( start_event );
16128         Sleep( 200 );
16129         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
16130         while (PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ))
16131         {
16132             GetMessageA( &msg, 0, 0, 0 );
16133             DispatchMessageA( &msg );
16134         }
16135         break;
16136     case 7:
16137         SetEvent( start_event );
16138         Sleep( 200 );
16139         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
16140         SetTimer( hwnd, 3, 1, NULL );
16141         Sleep( 200 );
16142         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
16143         break;
16144     case 8:
16145         SetEvent( start_event );
16146         Sleep( 200 );
16147         PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
16148         MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
16149         break;
16150     case 9:
16151         SetEvent( start_event );
16152         Sleep( 200 );
16153         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
16154         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
16155         for (;;) GetMessageA( &msg, 0, 0, 0 );
16156         break;
16157     case 10:
16158         SetEvent( start_event );
16159         Sleep( 200 );
16160         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
16161         SetTimer( hwnd, 3, 1, NULL );
16162         Sleep( 200 );
16163         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
16164         break;
16165     case 11:
16166         SetEvent( start_event );
16167         Sleep( 200 );
16168         return;  /* exiting the process makes WaitForInputIdle return success too */
16169     case 12:
16170         PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
16171         Sleep( 200 );
16172         MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
16173         SetEvent( start_event );
16174         break;
16175     case 13:
16176         SetEvent( start_event );
16177         PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
16178         Sleep( 200 );
16179         thread = CreateThread( NULL, 0, do_wait_idle_child_thread, NULL, 0, &id );
16180         WaitForSingleObject( thread, 10000 );
16181         CloseHandle( thread );
16182         break;
16183     case 14:
16184         SetEvent( start_event );
16185         Sleep( 200 );
16186         PeekMessageA( &msg, HWND_TOPMOST, 0, 0, PM_NOREMOVE );
16187         break;
16188     case 15:
16189         SetEvent( start_event );
16190         Sleep( 200 );
16191         PeekMessageA( &msg, HWND_BROADCAST, 0, 0, PM_NOREMOVE );
16192         break;
16193     case 16:
16194         SetEvent( start_event );
16195         Sleep( 200 );
16196         PeekMessageA( &msg, HWND_BOTTOM, 0, 0, PM_NOREMOVE );
16197         break;
16198     case 17:
16199         SetEvent( start_event );
16200         Sleep( 200 );
16201         PeekMessageA( &msg, (HWND)0xdeadbeef, 0, 0, PM_NOREMOVE );
16202         break;
16203     case 18:
16204         SetEvent( start_event );
16205         Sleep( 200 );
16206         PeekMessageA( &msg, HWND_NOTOPMOST, 0, 0, PM_NOREMOVE );
16207         break;
16208     case 19:
16209         SetEvent( start_event );
16210         Sleep( 200 );
16211         PeekMessageA( &msg, HWND_MESSAGE, 0, 0, PM_NOREMOVE );
16212         break;
16213     case 20:
16214         SetEvent( start_event );
16215         Sleep( 200 );
16216         PeekMessageA( &msg, GetDesktopWindow(), 0, 0, PM_NOREMOVE );
16217         break;
16218     }
16219     WaitForSingleObject( end_event, 2000 );
16220     CloseHandle( start_event );
16221     CloseHandle( end_event );
16222     if (hwnd) DestroyWindow( hwnd );
16223 }
16224 
16225 static LRESULT CALLBACK wait_idle_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
16226 {
16227     if (msg == WM_WININICHANGE) Sleep( 200 );  /* make sure the child waits */
16228     return DefWindowProcA( hwnd, msg, wp, lp );
16229 }
16230 
16231 static DWORD CALLBACK wait_idle_thread( void *arg )
16232 {
16233     WNDCLASSA cls;
16234     MSG msg;
16235     HWND hwnd;
16236 
16237     memset( &cls, 0, sizeof(cls) );
16238     cls.lpfnWndProc   = wait_idle_proc;
16239     cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
16240     cls.hCursor       = LoadCursorA(0, (LPCSTR)IDC_ARROW);
16241     cls.lpszClassName = "TestClass";
16242     RegisterClassA( &cls );
16243 
16244     hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL);
16245     while (GetMessageA( &msg, 0, 0, 0 )) DispatchMessageA( &msg );
16246     DestroyWindow(hwnd);
16247     return 0;
16248 }
16249 
16250 static void test_WaitForInputIdle( char *argv0 )
16251 {
16252     char path[MAX_PATH];
16253     PROCESS_INFORMATION pi;
16254     STARTUPINFOA startup;
16255     BOOL ret;
16256     HANDLE start_event, end_event, thread;
16257     unsigned int i;
16258     DWORD id;
16259     const IMAGE_DOS_HEADER *dos = (const IMAGE_DOS_HEADER *)GetModuleHandleA(0);
16260     const IMAGE_NT_HEADERS *nt = (const IMAGE_NT_HEADERS *)((const char *)dos + dos->e_lfanew);
16261     BOOL console_app = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_GUI);
16262 
16263     if (console_app)  /* build the test with -mwindows for better coverage */
16264         trace( "not built as a GUI app, WaitForInputIdle may not be fully tested\n" );
16265 
16266     start_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_start");
16267     end_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_end");
16268     ok(start_event != 0, "failed to create start event, error %u\n", GetLastError());
16269     ok(end_event != 0, "failed to create end event, error %u\n", GetLastError());
16270 
16271     memset( &startup, 0, sizeof(startup) );
16272     startup.cb = sizeof(startup);
16273     startup.dwFlags = STARTF_USESHOWWINDOW;
16274     startup.wShowWindow = SW_SHOWNORMAL;
16275 
16276     thread = CreateThread( NULL, 0, wait_idle_thread, NULL, 0, &id );
16277 
16278     for (i = 0; i < ARRAY_SIZE(wait_idle_expect); i++)
16279     {
16280         ResetEvent( start_event );
16281         ResetEvent( end_event );
16282 #ifdef __REACTOS__
16283         sprintf( path, "%s msg_queue %u", argv0, i );
16284 #else
16285         sprintf( path, "%s msg %u", argv0, i );
16286 #endif
16287         ret = CreateProcessA( NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &pi );
16288         ok( ret, "CreateProcess '%s' failed err %u.\n", path, GetLastError() );
16289         if (ret)
16290         {
16291             ret = WaitForSingleObject( start_event, 5000 );
16292             ok( ret == WAIT_OBJECT_0, "%u: WaitForSingleObject failed\n", i );
16293             if (ret == WAIT_OBJECT_0)
16294             {
16295                 ret = WaitForInputIdle( pi.hProcess, 1000 );
16296                 if (ret == WAIT_FAILED)
16297                     ok( console_app ||
16298                         ret == wait_idle_expect[i].exp ||
16299                         broken(ret == wait_idle_expect[i].broken),
16300                         "%u: WaitForInputIdle error %08x expected %08x\n",
16301                         i, ret, wait_idle_expect[i].exp );
16302                 else todo_wine_if (wait_idle_expect[i].todo)
16303                     ok( ret == wait_idle_expect[i].exp || broken(ret == wait_idle_expect[i].broken),
16304                         "%u: WaitForInputIdle error %08x expected %08x\n",
16305                         i, ret, wait_idle_expect[i].exp );
16306                 SetEvent( end_event );
16307                 WaitForSingleObject( pi.hProcess, 1000 );  /* give it a chance to exit on its own */
16308             }
16309             TerminateProcess( pi.hProcess, 0 );  /* just in case */
16310             winetest_wait_child_process( pi.hProcess );
16311             ret = WaitForInputIdle( pi.hProcess, 100 );
16312             ok( ret == WAIT_FAILED, "%u: WaitForInputIdle after exit error %08x\n", i, ret );
16313             CloseHandle( pi.hProcess );
16314             CloseHandle( pi.hThread );
16315         }
16316     }
16317     CloseHandle( start_event );
16318     PostThreadMessageA( id, WM_QUIT, 0, 0 );
16319     WaitForSingleObject( thread, 10000 );
16320     CloseHandle( thread );
16321 }
16322 
16323 static const struct message WmSetParentSeq_1[] = {
16324     { WM_SHOWWINDOW, sent|wparam, 0 },
16325     { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
16326     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
16327     { WM_CHILDACTIVATE, sent },
16328     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE },
16329     { WM_MOVE, sent|defwinproc|wparam, 0 },
16330     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
16331     { WM_SHOWWINDOW, sent|wparam, 1 },
16332     { 0 }
16333 };
16334 
16335 static const struct message WmSetParentSeq_2[] = {
16336     { WM_SHOWWINDOW, sent|wparam, 0 },
16337     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
16338     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
16339     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
16340     { HCBT_SETFOCUS, hook|optional },
16341     { WM_NCACTIVATE, sent|wparam|optional, 0 },
16342     { WM_ACTIVATE, sent|wparam|optional, 0 },
16343     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
16344     { WM_KILLFOCUS, sent|wparam, 0 },
16345     { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
16346     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
16347     { HCBT_ACTIVATE, hook|optional },
16348     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
16349     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
16350     { WM_NCACTIVATE, sent|wparam|optional, 1 },
16351     { WM_ACTIVATE, sent|wparam|optional, 1 },
16352     { HCBT_SETFOCUS, hook|optional },
16353     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
16354     { WM_SETFOCUS, sent|optional|defwinproc },
16355     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOCLIENTSIZE },
16356     { WM_MOVE, sent|defwinproc|wparam, 0 },
16357     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
16358     { WM_SHOWWINDOW, sent|wparam, 1 },
16359     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
16360     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
16361     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
16362     { 0 }
16363 };
16364 
16365 
16366 static void test_SetParent(void)
16367 {
16368     HWND parent1, parent2, child, popup;
16369     RECT rc, rc_old;
16370 
16371     parent1 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
16372                             100, 100, 200, 200, 0, 0, 0, NULL);
16373     ok(parent1 != 0, "Failed to create parent1 window\n");
16374 
16375     parent2 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
16376                             400, 100, 200, 200, 0, 0, 0, NULL);
16377     ok(parent2 != 0, "Failed to create parent2 window\n");
16378 
16379     /* WS_CHILD window */
16380     child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD | WS_VISIBLE,
16381                            10, 10, 150, 150, parent1, 0, 0, NULL);
16382     ok(child != 0, "Failed to create child window\n");
16383 
16384     GetWindowRect(parent1, &rc);
16385     trace("parent1 %s\n", wine_dbgstr_rect(&rc));
16386     GetWindowRect(child, &rc_old);
16387     MapWindowPoints(0, parent1, (POINT *)&rc_old, 2);
16388     trace("child %s\n", wine_dbgstr_rect(&rc_old));
16389 
16390     flush_sequence();
16391 
16392     SetParent(child, parent2);
16393     flush_events();
16394     ok_sequence(WmSetParentSeq_1, "SetParent() visible WS_CHILD", FALSE);
16395 
16396     ok(GetWindowLongA(child, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
16397     ok(!IsWindowVisible(child), "IsWindowVisible() should return FALSE\n");
16398 
16399     GetWindowRect(parent2, &rc);
16400     trace("parent2 %s\n", wine_dbgstr_rect(&rc));
16401     GetWindowRect(child, &rc);
16402     MapWindowPoints(0, parent2, (POINT *)&rc, 2);
16403     trace("child %s\n", wine_dbgstr_rect(&rc));
16404 
16405     ok(EqualRect(&rc_old, &rc), "rects do not match %s / %s\n", wine_dbgstr_rect(&rc_old),
16406        wine_dbgstr_rect(&rc));
16407 
16408     /* WS_POPUP window */
16409     popup = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP | WS_VISIBLE,
16410                            20, 20, 100, 100, 0, 0, 0, NULL);
16411     ok(popup != 0, "Failed to create popup window\n");
16412 
16413     GetWindowRect(popup, &rc_old);
16414     trace("popup %s\n", wine_dbgstr_rect(&rc_old));
16415 
16416     flush_sequence();
16417 
16418     SetParent(popup, child);
16419     flush_events();
16420     ok_sequence(WmSetParentSeq_2, "SetParent() visible WS_POPUP", TRUE);
16421 
16422     ok(GetWindowLongA(popup, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
16423     ok(!IsWindowVisible(popup), "IsWindowVisible() should return FALSE\n");
16424 
16425     GetWindowRect(child, &rc);
16426     trace("parent2 %s\n", wine_dbgstr_rect(&rc));
16427     GetWindowRect(popup, &rc);
16428     MapWindowPoints(0, child, (POINT *)&rc, 2);
16429     trace("popup %s\n", wine_dbgstr_rect(&rc));
16430 
16431     ok(EqualRect(&rc_old, &rc), "rects do not match %s / %s\n", wine_dbgstr_rect(&rc_old),
16432        wine_dbgstr_rect(&rc));
16433 
16434     DestroyWindow(popup);
16435     DestroyWindow(child);
16436     DestroyWindow(parent1);
16437     DestroyWindow(parent2);
16438 
16439     flush_sequence();
16440 }
16441 
16442 static const struct message WmKeyReleaseOnly[] = {
16443     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x80000001 },
16444     { WM_KEYUP, sent|wparam|lparam, 0x41, 0x80000001 },
16445     { 0 }
16446 };
16447 static const struct message WmKeyPressNormal[] = {
16448     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x1 },
16449     { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x1 },
16450     { 0 }
16451 };
16452 static const struct message WmKeyPressRepeat[] = {
16453     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x40000001 },
16454     { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x40000001 },
16455     { 0 }
16456 };
16457 static const struct message WmKeyReleaseNormal[] = {
16458     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0xc0000001 },
16459     { WM_KEYUP, sent|wparam|lparam, 0x41, 0xc0000001 },
16460     { 0 }
16461 };
16462 
16463 static void test_keyflags(void)
16464 {
16465     HWND test_window;
16466     SHORT key_state;
16467     BYTE keyboard_state[256];
16468     MSG msg;
16469 
16470     test_window = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
16471                            100, 100, 200, 200, 0, 0, 0, NULL);
16472 
16473     flush_events();
16474     flush_sequence();
16475 
16476     /* keyup without a keydown */
16477     keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
16478     while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16479         DispatchMessageA(&msg);
16480     ok_sequence(WmKeyReleaseOnly, "key release only", TRUE);
16481 
16482     key_state = GetAsyncKeyState(0x41);
16483     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16484 
16485     key_state = GetKeyState(0x41);
16486     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16487 
16488     /* keydown */
16489     keybd_event(0x41, 0, 0, 0);
16490     while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16491         DispatchMessageA(&msg);
16492     ok_sequence(WmKeyPressNormal, "key press only", FALSE);
16493 
16494     key_state = GetAsyncKeyState(0x41);
16495     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16496 
16497     key_state = GetKeyState(0x41);
16498     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16499 
16500     /* keydown repeat */
16501     keybd_event(0x41, 0, 0, 0);
16502     while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16503         DispatchMessageA(&msg);
16504     ok_sequence(WmKeyPressRepeat, "key press repeat", FALSE);
16505 
16506     key_state = GetAsyncKeyState(0x41);
16507     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16508 
16509     key_state = GetKeyState(0x41);
16510     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16511 
16512     /* keyup */
16513     keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
16514     while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16515         DispatchMessageA(&msg);
16516     ok_sequence(WmKeyReleaseNormal, "key release repeat", FALSE);
16517 
16518     key_state = GetAsyncKeyState(0x41);
16519     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16520 
16521     key_state = GetKeyState(0x41);
16522     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16523 
16524     /* set the key state in this thread */
16525     GetKeyboardState(keyboard_state);
16526     keyboard_state[0x41] = 0x80;
16527     SetKeyboardState(keyboard_state);
16528 
16529     key_state = GetAsyncKeyState(0x41);
16530     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16531 
16532     /* keydown */
16533     keybd_event(0x41, 0, 0, 0);
16534     while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16535         DispatchMessageA(&msg);
16536     ok_sequence(WmKeyPressRepeat, "key press after setkeyboardstate", TRUE);
16537 
16538     key_state = GetAsyncKeyState(0x41);
16539     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16540 
16541     key_state = GetKeyState(0x41);
16542     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16543 
16544     /* clear the key state in this thread */
16545     GetKeyboardState(keyboard_state);
16546     keyboard_state[0x41] = 0;
16547     SetKeyboardState(keyboard_state);
16548 
16549     key_state = GetAsyncKeyState(0x41);
16550     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16551 
16552     /* keyup */
16553     keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
16554     while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16555         DispatchMessageA(&msg);
16556     ok_sequence(WmKeyReleaseOnly, "key release after setkeyboardstate", TRUE);
16557 
16558     key_state = GetAsyncKeyState(0x41);
16559     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16560 
16561     key_state = GetKeyState(0x41);
16562     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16563 
16564     DestroyWindow(test_window);
16565     flush_sequence();
16566 }
16567 
16568 static const struct message WmHotkeyPressLWIN[] = {
16569     { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
16570     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
16571     { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
16572     { 0 }
16573 };
16574 static const struct message WmHotkeyPress[] = {
16575     { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16576     { WM_HOTKEY, sent|wparam, 5 },
16577     { 0 }
16578 };
16579 static const struct message WmHotkeyRelease[] = {
16580     { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16581     { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 0x80000001 },
16582     { WM_KEYUP, sent|lparam, 0, 0x80000001 },
16583     { 0 }
16584 };
16585 static const struct message WmHotkeyReleaseLWIN[] = {
16586     { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
16587     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
16588     { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
16589     { 0 }
16590 };
16591 static const struct message WmHotkeyCombined[] = {
16592     { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
16593     { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16594     { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16595     { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
16596     { WM_APP, sent, 0, 0 },
16597     { WM_HOTKEY, sent|wparam, 5 },
16598     { WM_APP+1, sent, 0, 0 },
16599     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
16600     { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
16601     { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
16602     { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
16603     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
16604     { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
16605     { 0 }
16606 };
16607 static const struct message WmHotkeyPrevious[] = {
16608     { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
16609     { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16610     { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16611     { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
16612     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
16613     { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
16614     { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 1 },
16615     { WM_KEYDOWN, sent|lparam, 0, 1 },
16616     { HCBT_KEYSKIPPED, hook|optional|lparam, 0, 0xc0000001 },
16617     { WM_KEYUP, sent|lparam, 0, 0xc0000001 },
16618     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
16619     { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
16620     { 0 }
16621 };
16622 static const struct message WmHotkeyNew[] = {
16623     { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16624     { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16625     { WM_HOTKEY, sent|wparam, 5 },
16626     { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
16627     { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
16628     { 0 }
16629 };
16630 
16631 static int hotkey_letter;
16632 
16633 static LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
16634 {
16635     struct recvd_message msg;
16636 
16637     if (nCode == HC_ACTION)
16638     {
16639         KBDLLHOOKSTRUCT *kdbhookstruct = (KBDLLHOOKSTRUCT*)lParam;
16640 
16641         msg.hwnd = 0;
16642         msg.message = wParam;
16643         msg.flags = kbd_hook|wparam|lparam;
16644         msg.wParam = kdbhookstruct->vkCode;
16645         msg.lParam = kdbhookstruct->flags;
16646         msg.descr = "KeyboardHookProc";
16647         add_message(&msg);
16648 
16649         if (wParam == WM_KEYUP || wParam == WM_KEYDOWN)
16650         {
16651             ok(kdbhookstruct->vkCode == VK_LWIN || kdbhookstruct->vkCode == hotkey_letter,
16652                "unexpected keycode %x\n", kdbhookstruct->vkCode);
16653        }
16654     }
16655 
16656     return CallNextHookEx(hKBD_hook, nCode, wParam, lParam);
16657 }
16658 
16659 static void test_hotkey(void)
16660 {
16661     HWND test_window, taskbar_window;
16662     BOOL ret;
16663     MSG msg;
16664     DWORD queue_status;
16665     SHORT key_state;
16666 
16667     SetLastError(0xdeadbeef);
16668     ret = UnregisterHotKey(NULL, 0);
16669     if (ret == TRUE)
16670     {
16671         skip("hotkeys not supported\n");
16672         return;
16673     }
16674 
16675     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16676     ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16677        "unexpected error %d\n", GetLastError());
16678 
16679     test_window = CreateWindowExA(0, "HotkeyWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
16680                            100, 100, 200, 200, 0, 0, 0, NULL);
16681 
16682     flush_sequence();
16683 
16684     SetLastError(0xdeadbeef);
16685     ret = UnregisterHotKey(test_window, 0);
16686     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16687     ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16688        "unexpected error %d\n", GetLastError());
16689 
16690     /* Search for a Windows Key + letter combination that hasn't been registered */
16691     for (hotkey_letter = 0x41; hotkey_letter <= 0x51; hotkey_letter ++)
16692     {
16693         SetLastError(0xdeadbeef);
16694         ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
16695 
16696         if (ret == TRUE)
16697         {
16698             break;
16699         }
16700         else
16701         {
16702             ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16703                "unexpected error %d\n", GetLastError());
16704         }
16705     }
16706 
16707     if (hotkey_letter == 0x52)
16708     {
16709         ok(0, "Couldn't find any free Windows Key + letter combination\n");
16710         goto end;
16711     }
16712 
16713     hKBD_hook = SetWindowsHookExA(WH_KEYBOARD_LL, KeyboardHookProc, GetModuleHandleA(NULL), 0);
16714     if (!hKBD_hook) win_skip("WH_KEYBOARD_LL is not supported\n");
16715 
16716     /* Same key combination, different id */
16717     SetLastError(0xdeadbeef);
16718     ret = RegisterHotKey(test_window, 4, MOD_WIN, hotkey_letter);
16719     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16720     ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16721        "unexpected error %d\n", GetLastError());
16722 
16723     /* Same key combination, different window */
16724     SetLastError(0xdeadbeef);
16725     ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
16726     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16727     ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16728        "unexpected error %d\n", GetLastError());
16729 
16730     /* Register the same hotkey twice */
16731     SetLastError(0xdeadbeef);
16732     ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
16733     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16734     ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16735        "unexpected error %d\n", GetLastError());
16736 
16737     /* Window on another thread */
16738     taskbar_window = FindWindowA("Shell_TrayWnd", NULL);
16739     if (!taskbar_window)
16740     {
16741         skip("no taskbar?\n");
16742     }
16743     else
16744     {
16745         SetLastError(0xdeadbeef);
16746         ret = RegisterHotKey(taskbar_window, 5, 0, hotkey_letter);
16747         ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16748         ok(GetLastError() == ERROR_WINDOW_OF_OTHER_THREAD || broken(GetLastError() == 0xdeadbeef),
16749            "unexpected error %d\n", GetLastError());
16750     }
16751 
16752     /* Inject the appropriate key sequence */
16753     keybd_event(VK_LWIN, 0, 0, 0);
16754     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16755         DispatchMessageA(&msg);
16756     ok_sequence(WmHotkeyPressLWIN, "window hotkey press LWIN", FALSE);
16757 
16758     keybd_event(hotkey_letter, 0, 0, 0);
16759     queue_status = GetQueueStatus(QS_HOTKEY);
16760     ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
16761     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16762     {
16763         if (msg.message == WM_HOTKEY)
16764         {
16765             ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
16766             ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
16767         }
16768         DispatchMessageA(&msg);
16769     }
16770     ok_sequence(WmHotkeyPress, "window hotkey press", FALSE);
16771 
16772     queue_status = GetQueueStatus(QS_HOTKEY);
16773     ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
16774 
16775     key_state = GetAsyncKeyState(hotkey_letter);
16776     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16777 
16778     keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16779     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16780         DispatchMessageA(&msg);
16781     ok_sequence(WmHotkeyRelease, "window hotkey release", TRUE);
16782 
16783     keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
16784     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16785         DispatchMessageA(&msg);
16786     ok_sequence(WmHotkeyReleaseLWIN, "window hotkey release LWIN", FALSE);
16787 
16788     /* normal posted WM_HOTKEY messages set QS_HOTKEY */
16789     PostMessageA(test_window, WM_HOTKEY, 0, 0);
16790     queue_status = GetQueueStatus(QS_HOTKEY);
16791     ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
16792     queue_status = GetQueueStatus(QS_POSTMESSAGE);
16793     ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
16794     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16795         DispatchMessageA(&msg);
16796     flush_sequence();
16797 
16798     /* Send and process all messages at once */
16799     PostMessageA(test_window, WM_APP, 0, 0);
16800     keybd_event(VK_LWIN, 0, 0, 0);
16801     keybd_event(hotkey_letter, 0, 0, 0);
16802     keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16803     keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
16804 
16805     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16806     {
16807         if (msg.message == WM_HOTKEY)
16808         {
16809             ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
16810             ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
16811         }
16812         DispatchMessageA(&msg);
16813     }
16814     ok_sequence(WmHotkeyCombined, "window hotkey combined", FALSE);
16815 
16816     /* Register same hwnd/id with different key combination */
16817     ret = RegisterHotKey(test_window, 5, 0, hotkey_letter);
16818     ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
16819 
16820     /* Previous key combination does not work */
16821     keybd_event(VK_LWIN, 0, 0, 0);
16822     keybd_event(hotkey_letter, 0, 0, 0);
16823     keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16824     keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
16825 
16826     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16827         DispatchMessageA(&msg);
16828     ok_sequence(WmHotkeyPrevious, "window hotkey previous", FALSE);
16829 
16830     /* New key combination works */
16831     keybd_event(hotkey_letter, 0, 0, 0);
16832     keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16833 
16834     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16835     {
16836         if (msg.message == WM_HOTKEY)
16837         {
16838             ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
16839             ok(msg.lParam == MAKELPARAM(0, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
16840         }
16841         DispatchMessageA(&msg);
16842     }
16843     ok_sequence(WmHotkeyNew, "window hotkey new", FALSE);
16844 
16845     /* Unregister hotkey properly */
16846     ret = UnregisterHotKey(test_window, 5);
16847     ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
16848 
16849     /* Unregister hotkey again */
16850     SetLastError(0xdeadbeef);
16851     ret = UnregisterHotKey(test_window, 5);
16852     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16853     ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16854        "unexpected error %d\n", GetLastError());
16855 
16856     /* Register thread hotkey */
16857     ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
16858     ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
16859 
16860     /* Inject the appropriate key sequence */
16861     keybd_event(VK_LWIN, 0, 0, 0);
16862     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16863     {
16864         ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
16865         DispatchMessageA(&msg);
16866     }
16867     ok_sequence(WmHotkeyPressLWIN, "thread hotkey press LWIN", FALSE);
16868 
16869     keybd_event(hotkey_letter, 0, 0, 0);
16870     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16871     {
16872         if (msg.message == WM_HOTKEY)
16873         {
16874             struct recvd_message message;
16875             ok(msg.hwnd == NULL, "unexpected hwnd %p\n", msg.hwnd);
16876             ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
16877             message.message = msg.message;
16878             message.flags = sent|wparam|lparam;
16879             message.wParam = msg.wParam;
16880             message.lParam = msg.lParam;
16881             message.descr = "test_hotkey thread message";
16882             add_message(&message);
16883         }
16884         else
16885             ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
16886         DispatchMessageA(&msg);
16887     }
16888     ok_sequence(WmHotkeyPress, "thread hotkey press", FALSE);
16889 
16890     keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16891     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16892     {
16893         ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
16894         DispatchMessageA(&msg);
16895     }
16896     ok_sequence(WmHotkeyRelease, "thread hotkey release", TRUE);
16897 
16898     keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
16899     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16900     {
16901         ros_skip_flaky
16902         ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
16903         DispatchMessageA(&msg);
16904     }
16905     ok_sequence(WmHotkeyReleaseLWIN, "thread hotkey release LWIN", FALSE);
16906 
16907     /* Unregister thread hotkey */
16908     ret = UnregisterHotKey(NULL, 5);
16909     ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
16910 
16911     if (hKBD_hook) UnhookWindowsHookEx(hKBD_hook);
16912     hKBD_hook = NULL;
16913 
16914 end:
16915     UnregisterHotKey(NULL, 5);
16916     UnregisterHotKey(test_window, 5);
16917     DestroyWindow(test_window);
16918     flush_sequence();
16919 }
16920 
16921 
16922 static const struct message WmSetFocus_1[] = {
16923     { HCBT_SETFOCUS, hook }, /* child */
16924     { HCBT_ACTIVATE, hook }, /* parent */
16925     { WM_QUERYNEWPALETTE, sent|wparam|lparam|parent|optional, 0, 0 },
16926     { WM_WINDOWPOSCHANGING, sent|parent, 0, SWP_NOSIZE|SWP_NOMOVE },
16927     { WM_ACTIVATEAPP, sent|wparam|parent, 1 },
16928     { WM_NCACTIVATE, sent|parent },
16929     { WM_GETTEXT, sent|defwinproc|parent|optional },
16930     { WM_GETTEXT, sent|defwinproc|parent|optional },
16931     { WM_ACTIVATE, sent|wparam|parent, 1 },
16932     { HCBT_SETFOCUS, hook }, /* parent */
16933     { WM_SETFOCUS, sent|defwinproc|parent },
16934     { WM_KILLFOCUS, sent|parent },
16935     { WM_SETFOCUS, sent },
16936     { 0 }
16937 };
16938 static const struct message WmSetFocus_2[] = {
16939     { HCBT_SETFOCUS, hook }, /* parent */
16940     { WM_KILLFOCUS, sent },
16941     { WM_SETFOCUS, sent|parent },
16942     { 0 }
16943 };
16944 static const struct message WmSetFocus_3[] = {
16945     { HCBT_SETFOCUS, hook }, /* child */
16946     { 0 }
16947 };
16948 
16949 static void test_SetFocus(void)
16950 {
16951     HWND parent, old_parent, child, old_focus, old_active;
16952     MSG msg;
16953     struct wnd_event wnd_event;
16954     HANDLE hthread;
16955     DWORD ret, tid;
16956 
16957     wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
16958     ok(wnd_event.start_event != 0, "CreateEvent error %d\n", GetLastError());
16959     hthread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
16960     ok(hthread != 0, "CreateThread error %d\n", GetLastError());
16961     ret = WaitForSingleObject(wnd_event.start_event, INFINITE);
16962     ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
16963     CloseHandle(wnd_event.start_event);
16964 
16965     parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
16966                             0, 0, 0, 0, 0, 0, 0, NULL);
16967     ok(parent != 0, "failed to create parent window\n");
16968     child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
16969                            0, 0, 0, 0, parent, 0, 0, NULL);
16970     ok(child != 0, "failed to create child window\n");
16971 
16972     trace("parent %p, child %p, thread window %p\n", parent, child, wnd_event.hwnd);
16973 
16974     SetFocus(0);
16975     SetActiveWindow(0);
16976 
16977     flush_events();
16978     flush_sequence();
16979 
16980     ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
16981     ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
16982 
16983     log_all_parent_messages++;
16984 
16985     old_focus = SetFocus(child);
16986     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16987     ok_sequence(WmSetFocus_1, "SetFocus on a child window", TRUE);
16988     ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
16989     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16990     ok(GetFocus() == child, "expected focus %p, got %p\n", child, GetFocus());
16991 
16992     old_focus = SetFocus(parent);
16993     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16994     ok_sequence(WmSetFocus_2, "SetFocus on a parent window", FALSE);
16995     ok(old_focus == child, "expected old focus %p, got %p\n", child, old_focus);
16996     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16997     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16998 
16999     SetLastError(0xdeadbeef);
17000     old_focus = SetFocus((HWND)0xdeadbeef);
17001     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
17002        "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
17003     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17004     ok_sequence(WmEmptySeq, "SetFocus on an invalid window", FALSE);
17005     ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
17006     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17007     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17008 
17009     SetLastError(0xdeadbeef);
17010     old_focus = SetFocus(GetDesktopWindow());
17011     ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
17012        broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
17013     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17014     ok_sequence(WmEmptySeq, "SetFocus on a desktop window", TRUE);
17015     ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
17016     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17017     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17018 
17019     SetLastError(0xdeadbeef);
17020     old_focus = SetFocus(wnd_event.hwnd);
17021     ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
17022        broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
17023     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17024     ok_sequence(WmEmptySeq, "SetFocus on another thread window", TRUE);
17025     ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
17026     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17027     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17028 
17029     SetLastError(0xdeadbeef);
17030     old_active = SetActiveWindow((HWND)0xdeadbeef);
17031     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
17032        "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
17033     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17034     ok_sequence(WmEmptySeq, "SetActiveWindow on an invalid window", FALSE);
17035     ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
17036     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17037     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17038 
17039     SetLastError(0xdeadbeef);
17040     old_active = SetActiveWindow(GetDesktopWindow());
17041 todo_wine
17042     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
17043     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17044     ok_sequence(WmEmptySeq, "SetActiveWindow on a desktop window", TRUE);
17045     ok(old_active == 0, "expected old focus 0, got %p\n", old_focus);
17046     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17047     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17048 
17049     SetLastError(0xdeadbeef);
17050     old_active = SetActiveWindow(wnd_event.hwnd);
17051 todo_wine
17052     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
17053     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17054     ok_sequence(WmEmptySeq, "SetActiveWindow on another thread window", TRUE);
17055     ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
17056     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17057     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17058 
17059     SetLastError(0xdeadbeef);
17060     ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE);
17061     ok(ret, "AttachThreadInput error %d\n", GetLastError());
17062 
17063     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17064     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17065 
17066     flush_events();
17067     flush_sequence();
17068 
17069     old_focus = SetFocus(wnd_event.hwnd);
17070     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17071     ok(old_focus == wnd_event.hwnd, "expected old focus %p, got %p\n", wnd_event.hwnd, old_focus);
17072     ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
17073     ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
17074 
17075     old_focus = SetFocus(parent);
17076     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17077     ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
17078     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17079     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17080 
17081     flush_events();
17082     flush_sequence();
17083 
17084     old_active = SetActiveWindow(wnd_event.hwnd);
17085     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17086     ok(old_active == parent, "expected old focus %p, got %p\n", parent, old_active);
17087     ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
17088     ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
17089 
17090     SetLastError(0xdeadbeef);
17091     ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE);
17092     ok(ret, "AttachThreadInput error %d\n", GetLastError());
17093 
17094     ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
17095     ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
17096 
17097     old_parent = SetParent(child, GetDesktopWindow());
17098     ok(old_parent == parent, "expected old parent %p, got %p\n", parent, old_parent);
17099 
17100     ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
17101     ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
17102 
17103     old_focus = SetFocus(parent);
17104     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17105     ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
17106     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17107     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17108 
17109     flush_events();
17110     flush_sequence();
17111 
17112     SetLastError(0xdeadbeef);
17113     old_focus = SetFocus(child);
17114 todo_wine
17115     ok(GetLastError() == ERROR_INVALID_PARAMETER /* Vista+ */ ||
17116        broken(GetLastError() == 0) /* XP */ ||
17117        broken(GetLastError() == 0xdeadbeef), "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
17118     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17119     ok_sequence(WmSetFocus_3, "SetFocus on a child window", TRUE);
17120     ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
17121     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17122     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17123 
17124     SetLastError(0xdeadbeef);
17125     old_active = SetActiveWindow(child);
17126     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
17127     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17128     ok_sequence(WmEmptySeq, "SetActiveWindow on a child window", FALSE);
17129     ok(old_active == parent, "expected old active %p, got %p\n", parent, old_active);
17130     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17131     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17132 
17133     log_all_parent_messages--;
17134 
17135     DestroyWindow(child);
17136     DestroyWindow(parent);
17137 
17138     ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
17139     ok(ret, "PostMessage(WM_QUIT) error %d\n", GetLastError());
17140     ret = WaitForSingleObject(hthread, INFINITE);
17141     ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
17142     CloseHandle(hthread);
17143 }
17144 
17145 static const struct message WmSetLayeredStyle[] = {
17146     { WM_STYLECHANGING, sent },
17147     { WM_STYLECHANGED, sent },
17148     { WM_GETTEXT, sent|defwinproc|optional },
17149     { 0 }
17150 };
17151 
17152 static const struct message WmSetLayeredStyle2[] = {
17153     { WM_STYLECHANGING, sent },
17154     { WM_STYLECHANGED, sent },
17155     { WM_WINDOWPOSCHANGING, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
17156     { WM_NCCALCSIZE, sent|optional|wparam|defwinproc, 1 },
17157     { WM_WINDOWPOSCHANGED, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
17158     { WM_MOVE, sent|optional|defwinproc|wparam, 0 },
17159     { WM_SIZE, sent|optional|defwinproc|wparam, SIZE_RESTORED },
17160     { 0 }
17161 };
17162 
17163 struct layered_window_info
17164 {
17165     HWND   hwnd;
17166     HDC    hdc;
17167     SIZE   size;
17168     HANDLE event;
17169     BOOL   ret;
17170 };
17171 
17172 static DWORD CALLBACK update_layered_proc( void *param )
17173 {
17174     struct layered_window_info *info = param;
17175     POINT src = { 0, 0 };
17176 
17177     info->ret = pUpdateLayeredWindow( info->hwnd, 0, NULL, &info->size,
17178                                       info->hdc, &src, 0, NULL, ULW_OPAQUE );
17179     ok( info->ret, "failed\n");
17180     SetEvent( info->event );
17181     return 0;
17182 }
17183 
17184 static void test_layered_window(void)
17185 {
17186     HWND hwnd;
17187     HDC hdc;
17188     HBITMAP bmp;
17189     BOOL ret;
17190     SIZE size;
17191     POINT pos, src;
17192     RECT rect, client;
17193     HANDLE thread;
17194     DWORD tid;
17195     struct layered_window_info info;
17196 
17197     if (!pUpdateLayeredWindow)
17198     {
17199         win_skip( "UpdateLayeredWindow not supported\n" );
17200         return;
17201     }
17202 
17203     hdc = CreateCompatibleDC( 0 );
17204     bmp = CreateCompatibleBitmap( hdc, 300, 300 );
17205     SelectObject( hdc, bmp );
17206 
17207     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_CAPTION | WS_THICKFRAME | WS_SYSMENU,
17208                            100, 100, 300, 300, 0, 0, 0, NULL);
17209     ok( hwnd != 0, "failed to create window\n" );
17210     ShowWindow( hwnd, SW_SHOWNORMAL );
17211     UpdateWindow( hwnd );
17212     flush_events();
17213     flush_sequence();
17214 
17215     GetWindowRect( hwnd, &rect );
17216     GetClientRect( hwnd, &client );
17217     ok( client.right < rect.right - rect.left, "wrong client area\n" );
17218     ok( client.bottom < rect.bottom - rect.top, "wrong client area\n" );
17219 
17220     src.x = src.y = 0;
17221     pos.x = pos.y = 300;
17222     size.cx = size.cy = 250;
17223     ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
17224     ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
17225     ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
17226     SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
17227     ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
17228 
17229     ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
17230     ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
17231     ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
17232     GetWindowRect( hwnd, &rect );
17233     ok( rect.left == 300 && rect.top == 300 && rect.right == 550 && rect.bottom == 550,
17234         "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
17235     GetClientRect( hwnd, &rect );
17236     ok( rect.right == client.right - 50 && rect.bottom == client.bottom - 50,
17237         "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
17238 
17239     size.cx = 150;
17240     pos.y = 200;
17241     ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
17242     ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
17243     ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
17244     GetWindowRect( hwnd, &rect );
17245     ok( rect.left == 300 && rect.top == 200 && rect.right == 450 && rect.bottom == 450,
17246         "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
17247     GetClientRect( hwnd, &rect );
17248     ok( rect.right == client.right - 150 && rect.bottom == client.bottom - 50,
17249         "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
17250 
17251     SetWindowLongA( hwnd, GWL_STYLE,
17252                    GetWindowLongA(hwnd, GWL_STYLE) & ~(WS_CAPTION | WS_THICKFRAME | WS_SYSMENU) );
17253     ok_sequence( WmSetLayeredStyle2, "WmSetLayeredStyle2", FALSE );
17254 
17255     size.cx = 200;
17256     pos.x = 200;
17257     ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
17258     ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
17259     ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
17260     GetWindowRect( hwnd, &rect );
17261     ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
17262         "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
17263     GetClientRect( hwnd, &rect );
17264     ok( (rect.right == 200 && rect.bottom == 250) ||
17265         broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
17266         "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
17267 
17268     size.cx = 0;
17269     ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
17270     ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
17271     ok( GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == ERROR_MR_MID_NOT_FOUND) ||
17272         broken(GetLastError() == ERROR_GEN_FAILURE) /* win7 */, "wrong error %u\n", GetLastError() );
17273     size.cx = 1;
17274     size.cy = -1;
17275     ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
17276     ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
17277     ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
17278 
17279     SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED );
17280     ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
17281     GetWindowRect( hwnd, &rect );
17282     ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
17283         "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
17284     GetClientRect( hwnd, &rect );
17285     ok( (rect.right == 200 && rect.bottom == 250) ||
17286         broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
17287         "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
17288 
17289     SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
17290     info.hwnd = hwnd;
17291     info.hdc = hdc;
17292     info.size.cx = 250;
17293     info.size.cy = 300;
17294     info.event = CreateEventA( NULL, TRUE, FALSE, NULL );
17295     info.ret = FALSE;
17296     thread = CreateThread( NULL, 0, update_layered_proc, &info, 0, &tid );
17297     ok( WaitForSingleObject( info.event, 1000 ) == 0, "wait failed\n" );
17298     ok( info.ret, "UpdateLayeredWindow failed in other thread\n" );
17299     WaitForSingleObject( thread, 1000 );
17300     CloseHandle( thread );
17301     GetWindowRect( hwnd, &rect );
17302     ok( rect.left == 200 && rect.top == 200 && rect.right == 450 && rect.bottom == 500,
17303         "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
17304     GetClientRect( hwnd, &rect );
17305     ok( (rect.right == 250 && rect.bottom == 300) ||
17306         broken(rect.right == client.right - 50 && rect.bottom == client.bottom),
17307         "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
17308 
17309     DestroyWindow( hwnd );
17310     DeleteDC( hdc );
17311     DeleteObject( bmp );
17312 }
17313 
17314 static HMENU hpopupmenu;
17315 
17316 static LRESULT WINAPI cancel_popup_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
17317 {
17318     if (ignore_message( message )) return 0;
17319 
17320     switch (message) {
17321     case WM_ENTERIDLE:
17322         todo_wine ok(GetCapture() == hwnd, "expected %p, got %p\n", hwnd, GetCapture());
17323         EndMenu();
17324         break;
17325     case WM_INITMENU:
17326     case WM_INITMENUPOPUP:
17327     case WM_UNINITMENUPOPUP:
17328         ok((HMENU)wParam == hpopupmenu, "expected %p, got %lx\n", hpopupmenu, wParam);
17329         break;
17330     case WM_CAPTURECHANGED:
17331         todo_wine ok(!lParam || (HWND)lParam == hwnd, "lost capture to %lx\n", lParam);
17332         break;
17333     }
17334 
17335     return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
17336 }
17337 
17338 static LRESULT WINAPI cancel_init_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
17339 {
17340     if (ignore_message( message )) return 0;
17341 
17342     switch (message) {
17343     case WM_ENTERMENULOOP:
17344         ok(EndMenu() == TRUE, "EndMenu() failed\n");
17345         break;
17346     }
17347 
17348     return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
17349 }
17350 
17351 static void test_TrackPopupMenu(void)
17352 {
17353     MSG msg;
17354     HWND hwnd;
17355     BOOL ret;
17356 
17357     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
17358                            0, 0, 1, 1, 0,
17359                            NULL, NULL, 0);
17360     ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
17361 
17362     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
17363 
17364     hpopupmenu = CreatePopupMenu();
17365     ok(hpopupmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
17366 
17367     AppendMenuA(hpopupmenu, MF_STRING, 100, "item 1");
17368     AppendMenuA(hpopupmenu, MF_STRING, 100, "item 2");
17369 
17370     flush_events();
17371     flush_sequence();
17372     ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
17373     ok_sequence(WmTrackPopupMenu, "TrackPopupMenu", TRUE);
17374     ok(ret == 1, "TrackPopupMenu failed with error %i\n", GetLastError());
17375 
17376     /* Test popup closing with an ESC-press */
17377     flush_events();
17378     PostMessageW(hwnd, WM_KEYDOWN, VK_ESCAPE, 0);
17379     ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
17380     ok(ret == 1, "TrackPopupMenu failed with error %i\n", GetLastError());
17381     PostQuitMessage(0);
17382     flush_sequence();
17383     while ( PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) )
17384     {
17385         TranslateMessage(&msg);
17386         DispatchMessageA(&msg);
17387     }
17388     ok_sequence(WmTrackPopupMenuEsc, "TrackPopupMenuEsc", FALSE); /* Shouldn't get any message */
17389 
17390     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_init_proc);
17391 
17392     flush_events();
17393     flush_sequence();
17394     ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
17395     ok_sequence(WmTrackPopupMenuAbort, "WmTrackPopupMenuAbort", TRUE);
17396     ok(ret == TRUE, "TrackPopupMenu failed\n");
17397 
17398     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
17399 
17400     SetCapture(hwnd);
17401 
17402     flush_events();
17403     flush_sequence();
17404     ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
17405     ok_sequence(WmTrackPopupMenuCapture, "TrackPopupMenuCapture", TRUE);
17406     ok(ret == 1, "TrackPopupMenuCapture failed with error %i\n", GetLastError());
17407 
17408     DestroyMenu(hpopupmenu);
17409     DestroyWindow(hwnd);
17410 }
17411 
17412 static void test_TrackPopupMenuEmpty(void)
17413 {
17414     HWND hwnd;
17415     BOOL ret;
17416 
17417     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
17418                            0, 0, 1, 1, 0,
17419                            NULL, NULL, 0);
17420     ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
17421 
17422     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
17423 
17424     hpopupmenu = CreatePopupMenu();
17425     ok(hpopupmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
17426 
17427     flush_events();
17428     flush_sequence();
17429     ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
17430     ok_sequence(WmTrackPopupMenuEmpty, "TrackPopupMenuEmpty", TRUE);
17431     ok(ret == 0, "TrackPopupMenu succeeded\n");
17432 
17433     DestroyMenu(hpopupmenu);
17434     DestroyWindow(hwnd);
17435 }
17436 
17437 static const struct message send_message_1[] = {
17438     { WM_USER+2, sent|wparam|lparam, 0, 0 },
17439     { WM_USER, sent|wparam|lparam, 0, 0 },
17440     { 0 }
17441 };
17442 static const struct message send_message_2[] = {
17443     { WM_USER+4, sent|wparam|lparam, 0, 0 },
17444     { 0 }
17445 };
17446 static const struct message send_message_3[] = {
17447     { WM_USER+3, sent|wparam|lparam, 0, 0 },
17448     { WM_USER+1, sent|wparam|lparam, 0, 0 },
17449     { 0 }
17450 };
17451 
17452 static DWORD WINAPI SendMessage_thread_1(void *param)
17453 {
17454     struct wnd_event *wnd_event = param;
17455 
17456     trace("thread: starting\n");
17457     WaitForSingleObject(wnd_event->start_event, INFINITE);
17458 
17459     trace("thread: call PostMessage\n");
17460     PostMessageA(wnd_event->hwnd, WM_USER, 0, 0);
17461 
17462     trace("thread: call PostMessage\n");
17463     PostMessageA(wnd_event->hwnd, WM_USER+1, 0, 0);
17464 
17465     trace("thread: call SendMessage\n");
17466     SendMessageA(wnd_event->hwnd, WM_USER+2, 0, 0);
17467 
17468     trace("thread: call SendMessage\n");
17469     SendMessageA(wnd_event->hwnd, WM_USER+3, 0, 0);
17470 
17471     return 0;
17472 }
17473 
17474 static DWORD WINAPI SendMessage_thread_2(void *param)
17475 {
17476     struct wnd_event *wnd_event = param;
17477 
17478     trace("thread: starting\n");
17479     WaitForSingleObject(wnd_event->start_event, INFINITE);
17480 
17481     trace("thread: call PostMessage\n");
17482     PostMessageA(wnd_event->hwnd, WM_USER, 0, 0);
17483 
17484     trace("thread: call PostMessage\n");
17485     PostMessageA(wnd_event->hwnd, WM_USER+1, 0, 0);
17486 
17487     /* this leads to sending an internal message under Wine */
17488     trace("thread: call SetParent\n");
17489     SetParent(wnd_event->hwnd, wnd_event->hwnd);
17490 
17491     trace("thread: call SendMessage\n");
17492     SendMessageA(wnd_event->hwnd, WM_USER+2, 0, 0);
17493 
17494     trace("thread: call SendMessage\n");
17495     SendMessageA(wnd_event->hwnd, WM_USER+3, 0, 0);
17496 
17497     return 0;
17498 }
17499 
17500 static void test_SendMessage_other_thread(int thread_n)
17501 {
17502     DWORD qs_all_input = QS_ALLINPUT & ~QS_RAWINPUT;
17503     HANDLE hthread;
17504     struct wnd_event wnd_event;
17505     DWORD tid, ret;
17506     MSG msg;
17507 
17508     wnd_event.start_event = CreateEventA(NULL, 0, 0, NULL);
17509 
17510     wnd_event.hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
17511                                      100, 100, 200, 200, 0, 0, 0, NULL);
17512     ok(wnd_event.hwnd != 0, "CreateWindowEx failed\n");
17513 
17514     hthread = CreateThread(NULL, 0, thread_n == 1 ? SendMessage_thread_1 : SendMessage_thread_2, &wnd_event, 0, &tid);
17515     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
17516     CloseHandle(hthread);
17517 
17518     flush_events();
17519     flush_sequence();
17520 
17521     ret = GetQueueStatus(QS_SENDMESSAGE);
17522     ok(ret == 0, "wrong status %08x\n", ret);
17523 
17524     SetEvent(wnd_event.start_event);
17525 
17526     /* wait for other thread's SendMessage */
17527     for (;;)
17528     {
17529         ret = GetQueueStatus(QS_SENDMESSAGE);
17530         if (ret == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE)) break;
17531         Sleep(50);
17532     }
17533 
17534     ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17535     ok(ret == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE), "wrong status %08x\n", ret);
17536 
17537     trace("main: call GetMessage\n");
17538     GetMessageA(&msg, 0, 0, 0);
17539     ok(msg.message == WM_USER, "expected WM_USER, got %04x\n", msg.message);
17540     DispatchMessageA(&msg);
17541     ok_sequence(send_message_1, "SendMessage from other thread 1", thread_n == 2);
17542 
17543     /* intentionally yield */
17544     MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input);
17545 
17546     trace("main: call SendMessage\n");
17547     SendMessageA(wnd_event.hwnd, WM_USER+4, 0, 0);
17548     ok_sequence(send_message_2, "SendMessage from other thread 2", FALSE);
17549 
17550     ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17551     ok(ret == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE), "wrong status %08x\n", ret);
17552 
17553     trace("main: call PeekMessage\n");
17554     ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should not fail\n");
17555     ok(msg.message == WM_USER+1, "expected WM_USER+1, got %04x\n", msg.message);
17556     DispatchMessageA(&msg);
17557     ok_sequence(send_message_3, "SendMessage from other thread 3", thread_n == 2);
17558 
17559     /* intentionally yield */
17560     MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input);
17561 
17562     ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17563     /* FIXME: remove once Wine is fixed */
17564 todo_wine_if (thread_n == 2)
17565     ok(ret == 0, "wrong status %08x\n", ret);
17566 
17567     trace("main: call PeekMessage\n");
17568     ok(!PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should fail\n");
17569     ok_sequence(WmEmptySeq, "SendMessage from other thread 5", thread_n == 2);
17570 
17571     ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17572     ok(ret == 0, "wrong status %08x\n", ret);
17573 
17574     trace("main: call DestroyWindow\n");
17575     DestroyWindow(msg.hwnd);
17576 
17577     flush_events();
17578     flush_sequence();
17579 }
17580 
17581 static LRESULT CALLBACK insendmessage_wnd_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
17582 {
17583     DWORD flags = InSendMessageEx( NULL );
17584     BOOL ret;
17585 
17586     switch (msg)
17587     {
17588     case WM_USER:
17589         ok( flags == ISMEX_SEND, "wrong flags %x\n", flags );
17590         ok( InSendMessage(), "InSendMessage returned false\n" );
17591         ret = ReplyMessage( msg );
17592         ok( ret, "ReplyMessage failed err %u\n", GetLastError() );
17593         flags = InSendMessageEx( NULL );
17594         ok( flags == (ISMEX_SEND | ISMEX_REPLIED), "wrong flags %x\n", flags );
17595         ok( InSendMessage(), "InSendMessage returned false\n" );
17596         break;
17597     case WM_USER + 1:
17598         ok( flags == ISMEX_NOTIFY, "wrong flags %x\n", flags );
17599         ok( InSendMessage(), "InSendMessage returned false\n" );
17600         ret = ReplyMessage( msg );
17601         ok( ret, "ReplyMessage failed err %u\n", GetLastError() );
17602         flags = InSendMessageEx( NULL );
17603         ok( flags == ISMEX_NOTIFY, "wrong flags %x\n", flags );
17604         ok( InSendMessage(), "InSendMessage returned false\n" );
17605         break;
17606     case WM_USER + 2:
17607         ok( flags == ISMEX_CALLBACK, "wrong flags %x\n", flags );
17608         ok( InSendMessage(), "InSendMessage returned false\n" );
17609         ret = ReplyMessage( msg );
17610         ok( ret, "ReplyMessage failed err %u\n", GetLastError() );
17611         flags = InSendMessageEx( NULL );
17612         ok( flags == (ISMEX_CALLBACK | ISMEX_REPLIED) || flags == ISMEX_SEND, "wrong flags %x\n", flags );
17613         ok( InSendMessage(), "InSendMessage returned false\n" );
17614         break;
17615     case WM_USER + 3:
17616         ok( flags == ISMEX_NOSEND, "wrong flags %x\n", flags );
17617         ok( !InSendMessage(), "InSendMessage returned true\n" );
17618         ret = ReplyMessage( msg );
17619         ok( !ret, "ReplyMessage succeeded\n" );
17620         break;
17621     }
17622 
17623     return DefWindowProcA( hwnd, msg, wp, lp );
17624 }
17625 
17626 static void CALLBACK msg_callback( HWND hwnd, UINT msg, ULONG_PTR arg, LRESULT result )
17627 {
17628     ok( msg == WM_USER + 2, "wrong msg %x\n", msg );
17629     ok( result == WM_USER + 2, "wrong result %lx\n", result );
17630 }
17631 
17632 static DWORD WINAPI send_message_thread( void *arg )
17633 {
17634     HWND win = arg;
17635 
17636     SendMessageA( win, WM_USER, 0, 0 );
17637     SendNotifyMessageA( win, WM_USER + 1, 0, 0 );
17638     SendMessageCallbackA( win, WM_USER + 2, 0, 0, msg_callback, 0 );
17639     PostMessageA( win, WM_USER + 3, 0, 0 );
17640     PostMessageA( win, WM_QUIT, 0, 0 );
17641     return 0;
17642 }
17643 
17644 static void test_InSendMessage(void)
17645 {
17646     WNDCLASSA cls;
17647     HWND win;
17648     MSG msg;
17649     HANDLE thread;
17650     DWORD tid;
17651 
17652     memset(&cls, 0, sizeof(cls));
17653     cls.lpfnWndProc = insendmessage_wnd_proc;
17654     cls.hInstance = GetModuleHandleA(NULL);
17655     cls.lpszClassName = "InSendMessage_test";
17656     RegisterClassA(&cls);
17657 
17658     win = CreateWindowA( "InSendMessage_test", NULL, 0, 0, 0, 0, 0, NULL, 0, NULL, 0 );
17659     ok( win != NULL, "CreateWindow failed: %d\n", GetLastError() );
17660 
17661     thread = CreateThread( NULL, 0, send_message_thread, win, 0, &tid );
17662     ok( thread != NULL, "CreateThread failed: %d\n", GetLastError() );
17663 
17664     while (GetMessageA(&msg, NULL, 0, 0)) DispatchMessageA( &msg );
17665 
17666     ok( WaitForSingleObject( thread, 30000 ) == WAIT_OBJECT_0, "WaitForSingleObject failed\n" );
17667     CloseHandle( thread );
17668 
17669     DestroyWindow( win );
17670     UnregisterClassA( "InSendMessage_test", GetModuleHandleA(NULL) );
17671 }
17672 
17673 static const struct message DoubleSetCaptureSeq[] =
17674 {
17675     { WM_CAPTURECHANGED, sent },
17676     { 0 }
17677 };
17678 
17679 static void test_DoubleSetCapture(void)
17680 {
17681     HWND hwnd;
17682 
17683     hwnd = CreateWindowExA(0, "TestWindowClass", "Test DoubleSetCapture",
17684                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
17685                            100, 100, 200, 200, 0, 0, 0, NULL);
17686     ok (hwnd != 0, "Failed to create overlapped window\n");
17687 
17688     ShowWindow( hwnd, SW_SHOW );
17689     UpdateWindow( hwnd );
17690     flush_events();
17691     flush_sequence();
17692 
17693     SetCapture( hwnd );
17694     SetCapture( hwnd );
17695     ok_sequence(DoubleSetCaptureSeq, "SetCapture( hwnd ) twice", FALSE);
17696 
17697     DestroyWindow(hwnd);
17698 }
17699 
17700 static const struct message WmRestoreMinimizedSeq[] =
17701 {
17702     { HCBT_ACTIVATE, hook },
17703     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
17704     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
17705     { WM_ACTIVATEAPP, sent|wparam, 1 },
17706     { WM_NCACTIVATE, sent|wparam, 0x200001 },
17707     { WM_GETTEXT, sent|defwinproc|optional },
17708     { WM_ACTIVATE, sent|wparam, 0x200001 }, /* Note that activate messages are after WM_WINDOWPOSCHANGED and before WM_SYSCOMMAND */
17709     { HCBT_KEYSKIPPED, hook|optional },
17710     { WM_SYSKEYUP, sent|optional },
17711     { WM_SYSCOMMAND, sent|wparam, SC_RESTORE },
17712     { HCBT_SYSCOMMAND, hook|wparam, SC_RESTORE },
17713     { HCBT_SYSCOMMAND, hook|wparam|optional, SC_RESTORE },
17714     { HCBT_MINMAX, hook },
17715     { HCBT_MINMAX, hook|optional },
17716     { WM_QUERYOPEN, sent|defwinproc },
17717     { WM_QUERYOPEN, sent|optional },
17718     { WM_GETTEXT, sent|defwinproc|optional },
17719     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
17720     { WM_GETMINMAXINFO, sent|defwinproc },
17721     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
17722     { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
17723     { WM_GETTEXT, sent|defwinproc|optional },
17724     { WM_ERASEBKGND, sent|defwinproc },
17725     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
17726     { WM_MOVE, sent|defwinproc },
17727     { WM_SIZE, sent|defwinproc },
17728     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
17729     { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
17730     { WM_ERASEBKGND, sent|defwinproc|optional },
17731     { HCBT_SETFOCUS, hook },
17732     { WM_SETFOCUS, sent|defwinproc },
17733     { WM_ACTIVATE, sent|wparam|defwinproc, 1 },
17734     { WM_PAINT, sent| optional },
17735     { WM_SETFOCUS, sent|defwinproc|optional },
17736     { HCBT_KEYSKIPPED, hook|optional },
17737     { WM_KEYUP, sent|optional },
17738     { HCBT_KEYSKIPPED, hook|optional },
17739     { WM_SYSKEYUP, sent|optional },
17740     { HCBT_KEYSKIPPED, hook|optional },
17741     { WM_KEYUP, sent|optional },
17742     { WM_PAINT, sent| optional },
17743     { 0 }
17744 };
17745 
17746 static void test_restore_messages(void)
17747 {
17748     INPUT ip = {0};
17749     HWND hwnd;
17750     INT i;
17751 
17752     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100,
17753                            100, 200, 200, 0, 0, 0, NULL);
17754     ok (hwnd != 0, "Failed to create overlapped window\n");
17755     SetForegroundWindow(hwnd);
17756     ShowWindow(hwnd, SW_MINIMIZE);
17757     flush_events();
17758     flush_sequence();
17759 
17760     for (i = 0; i < 5; i++)
17761     {
17762         /* Send Alt+Tab to restore test window from minimized state */
17763         ip.type = INPUT_KEYBOARD;
17764         ip.ki.wVk = VK_MENU;
17765         SendInput(1, &ip, sizeof(INPUT));
17766         ip.ki.wVk = VK_TAB;
17767         SendInput(1, &ip, sizeof(INPUT));
17768         ip.ki.wVk = VK_MENU;
17769         ip.ki.dwFlags = KEYEVENTF_KEYUP;
17770         SendInput(1, &ip, sizeof(INPUT));
17771         ip.ki.wVk = VK_TAB;
17772         ip.ki.dwFlags = KEYEVENTF_KEYUP;
17773         SendInput(1, &ip, sizeof(INPUT));
17774         flush_events();
17775         if (!IsIconic(hwnd))
17776             break;
17777     }
17778 
17779     if (IsIconic(hwnd))
17780     {
17781         skip("Alt+Tab failed to bring up test window.\n");
17782         goto done;
17783     }
17784     ok_sequence(WmRestoreMinimizedSeq, "Restore minimized window", TRUE);
17785 
17786 done:
17787     DestroyWindow(hwnd);
17788 }
17789 
17790 static void test_invalid_window(void)
17791 {
17792     MSG msg;
17793     BOOL ret;
17794 
17795     SetLastError(0xdeadbeef);
17796     ret = GetMessageA(&msg, (HWND)0xdeadbeef, 0, 0);
17797     ok(ret == -1, "wrong ret %d\n", ret);
17798     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError());
17799 
17800     SetLastError(0xdeadbeef);
17801     ret = PeekMessageA(&msg, (HWND)0xdeadbeef, 0, 0, PM_REMOVE);
17802     ok(!ret, "wrong ret %d\n", ret);
17803     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError());
17804 }
17805 
17806 static void init_funcs(void)
17807 {
17808     HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
17809 
17810 #define X(f) p##f = (void*)GetProcAddress(hKernel32, #f)
17811     X(ActivateActCtx);
17812     X(CreateActCtxW);
17813     X(DeactivateActCtx);
17814     X(GetCurrentActCtx);
17815     X(QueryActCtxW);
17816     X(ReleaseActCtx);
17817 #undef X
17818 }
17819 
17820 #ifndef __REACTOS__
17821 START_TEST(msg)
17822 {
17823     char **test_argv;
17824     BOOL ret;
17825     BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
17826     HMODULE hModuleImm32;
17827     BOOL (WINAPI *pImmDisableIME)(DWORD);
17828     int argc;
17829 
17830     init_funcs();
17831 
17832     argc = winetest_get_mainargs( &test_argv );
17833     if (argc >= 3)
17834     {
17835         unsigned int arg;
17836         /* Child process. */
17837         sscanf (test_argv[2], "%d", (unsigned int *) &arg);
17838         do_wait_idle_child( arg );
17839         return;
17840     }
17841 
17842     InitializeCriticalSection( &sequence_cs );
17843     init_procs();
17844 
17845     hModuleImm32 = LoadLibraryA("imm32.dll");
17846     if (hModuleImm32) {
17847         pImmDisableIME = (void *)GetProcAddress(hModuleImm32, "ImmDisableIME");
17848         if (pImmDisableIME)
17849             pImmDisableIME(0);
17850     }
17851     pImmDisableIME = NULL;
17852     FreeLibrary(hModuleImm32);
17853 
17854     if (!RegisterWindowClasses()) assert(0);
17855 
17856     if (pSetWinEventHook)
17857     {
17858         hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
17859                                        GetModuleHandleA(0), win_event_proc,
17860                                        0, GetCurrentThreadId(),
17861                                        WINEVENT_INCONTEXT);
17862         if (pIsWinEventHookInstalled && hEvent_hook)
17863 	{
17864 	    UINT event;
17865 	    for (event = EVENT_MIN; event <= EVENT_MAX; event++)
17866 		ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
17867 	}
17868     }
17869     if (!hEvent_hook) win_skip( "no win event hook support\n" );
17870 
17871     cbt_hook_thread_id = GetCurrentThreadId();
17872     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
17873     if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
17874 
17875     test_winevents();
17876 
17877     /* Fix message sequences before removing 4 lines below */
17878     if (pUnhookWinEvent && hEvent_hook)
17879     {
17880         ret = pUnhookWinEvent(hEvent_hook);
17881         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
17882         pUnhookWinEvent = 0;
17883     }
17884     hEvent_hook = 0;
17885 
17886     test_SendMessage_other_thread(1);
17887     test_SendMessage_other_thread(2);
17888     test_InSendMessage();
17889     test_SetFocus();
17890     test_SetParent();
17891     test_PostMessage();
17892     test_broadcast();
17893     test_ShowWindow();
17894     test_PeekMessage();
17895     test_PeekMessage2();
17896     test_PeekMessage3();
17897     test_WaitForInputIdle( test_argv[0] );
17898     test_scrollwindowex();
17899     test_messages();
17900     test_setwindowpos();
17901     test_showwindow();
17902     test_recursive_activation();
17903     invisible_parent_tests();
17904     test_mdi_messages();
17905     test_button_messages();
17906     test_button_bm_get_set_image();
17907     test_autoradio_BM_CLICK();
17908     test_autoradio_kbd_move();
17909     test_static_messages();
17910     test_listbox_messages();
17911     test_combobox_messages();
17912     test_wmime_keydown_message();
17913     test_paint_messages();
17914     test_interthread_messages();
17915     test_message_conversion();
17916     test_accelerators();
17917     test_timers();
17918     test_timers_no_wnd();
17919     test_timers_exceptions();
17920     if (hCBT_hook)
17921     {
17922         test_set_hook();
17923         test_recursive_hook();
17924     }
17925     test_DestroyWindow();
17926     test_DispatchMessage();
17927     test_SendMessageTimeout();
17928     test_edit_messages();
17929     test_quit_message();
17930     test_notify_message();
17931     test_SetActiveWindow();
17932     test_restore_messages();
17933     test_invalid_window();
17934 
17935     if (!pTrackMouseEvent)
17936         win_skip("TrackMouseEvent is not available\n");
17937     else
17938         test_TrackMouseEvent();
17939 
17940     test_SetWindowRgn();
17941     test_sys_menu();
17942     test_dialog_messages();
17943     test_EndDialog();
17944     test_nullCallback();
17945     test_dbcs_wm_char();
17946     test_unicode_wm_char();
17947     test_menu_messages();
17948     test_paintingloop();
17949     test_defwinproc();
17950     test_desktop_winproc();
17951     test_clipboard_viewers();
17952     test_keyflags();
17953     test_hotkey();
17954     test_layered_window();
17955     test_TrackPopupMenu();
17956     test_TrackPopupMenuEmpty();
17957     test_DoubleSetCapture();
17958     /* keep it the last test, under Windows it tends to break the tests
17959      * which rely on active/foreground windows being correct.
17960      */
17961     test_SetForegroundWindow();
17962 
17963     UnhookWindowsHookEx(hCBT_hook);
17964     if (pUnhookWinEvent && hEvent_hook)
17965     {
17966 	ret = pUnhookWinEvent(hEvent_hook);
17967 	ok( ret, "UnhookWinEvent error %d\n", GetLastError());
17968 	SetLastError(0xdeadbeef);
17969 	ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
17970 	ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
17971 	   GetLastError() == 0xdeadbeef, /* Win9x */
17972            "unexpected error %d\n", GetLastError());
17973     }
17974     DeleteCriticalSection( &sequence_cs );
17975 }
17976 #endif /* __REACTOS__ */
17977 
17978 static void init_tests()
17979 {
17980     HMODULE hModuleImm32;
17981     BOOL (WINAPI *pImmDisableIME)(DWORD);
17982 
17983     init_funcs();
17984 
17985     InitializeCriticalSection( &sequence_cs );
17986     init_procs();
17987 
17988     hModuleImm32 = LoadLibraryA("imm32.dll");
17989     if (hModuleImm32) {
17990         pImmDisableIME = (void *)GetProcAddress(hModuleImm32, "ImmDisableIME");
17991         if (pImmDisableIME)
17992             pImmDisableIME(0);
17993     }
17994     pImmDisableIME = NULL;
17995     FreeLibrary(hModuleImm32);
17996 
17997     if (!RegisterWindowClasses()) assert(0);
17998 
17999     cbt_hook_thread_id = GetCurrentThreadId();
18000     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
18001     if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
18002 }
18003 
18004 static void cleanup_tests()
18005 {
18006     BOOL ret;
18007     UnhookWindowsHookEx(hCBT_hook);
18008     if (pUnhookWinEvent && hEvent_hook)
18009     {
18010         ret = pUnhookWinEvent(hEvent_hook);
18011         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
18012         SetLastError(0xdeadbeef);
18013         ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
18014         ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
18015            GetLastError() == 0xdeadbeef, /* Win9x */
18016            "unexpected error %d\n", GetLastError());
18017     }
18018     DeleteCriticalSection( &sequence_cs );
18019 
18020 }
18021 
18022 START_TEST(msg_queue)
18023 {
18024     int argc;
18025     char **test_argv;
18026     argc = winetest_get_mainargs( &test_argv );
18027     if (argc >= 3)
18028     {
18029         unsigned int arg;
18030         /* Child process. */
18031         sscanf (test_argv[2], "%d", (unsigned int *) &arg);
18032         do_wait_idle_child( arg );
18033         return;
18034     }
18035 
18036     init_tests();
18037     test_SendMessage_other_thread(1);
18038     test_SendMessage_other_thread(2);
18039     test_InSendMessage();
18040     test_PostMessage();
18041     test_broadcast();
18042     test_PeekMessage();
18043     test_PeekMessage2();
18044     test_PeekMessage3();
18045     test_interthread_messages();
18046     test_DispatchMessage();
18047     test_SendMessageTimeout();
18048     test_quit_message();
18049     test_notify_message();
18050     test_WaitForInputIdle( test_argv[0] );
18051     test_DestroyWindow();
18052     cleanup_tests();
18053 }
18054 
18055 START_TEST(msg_messages)
18056 {
18057     init_tests();
18058     test_message_conversion();
18059     test_messages();
18060     test_wmime_keydown_message();
18061     test_nullCallback();
18062     test_dbcs_wm_char();
18063     test_unicode_wm_char();
18064     test_defwinproc();
18065     test_desktop_winproc();
18066     cleanup_tests();
18067 }
18068 
18069 START_TEST(msg_focus)
18070 {
18071     init_tests();
18072 
18073     test_SetFocus();
18074 
18075     /* HACK: For some reason the tests fail on Windows if run consecutively.
18076      * Putting these in between helps, and is essentially what happens in the
18077      * "normal" msg test. */
18078     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
18079     flush_events();
18080 
18081     test_SetActiveWindow();
18082 
18083     /* HACK */
18084     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
18085     flush_events();
18086 
18087     test_restore_messages();
18088     test_invalid_window();
18089 
18090     test_DoubleSetCapture();
18091 
18092     /* keep it the last test, under Windows it tends to break the tests
18093      * which rely on active/foreground windows being correct.
18094      */
18095     test_SetForegroundWindow();
18096     cleanup_tests();
18097 }
18098 
18099 START_TEST(msg_winpos)
18100 {
18101     init_tests();
18102     test_SetParent();
18103     test_ShowWindow();
18104     test_setwindowpos();
18105     test_showwindow();
18106     test_recursive_activation();
18107     test_SetWindowRgn();
18108     invisible_parent_tests();
18109     cleanup_tests();
18110 }
18111 
18112 START_TEST(msg_paint)
18113 {
18114     init_tests();
18115     test_scrollwindowex();
18116     test_paint_messages();
18117 #ifdef __REACTOS__
18118     if (!winetest_interactive &&
18119         !strcmp(winetest_platform, "windows"))
18120     {
18121         skip("ROSTESTS-185: Skipping user32_winetest:msg_paint test_paintingloop because it hangs on WHS-Testbot. Set winetest_interactive to run it anyway.\n");
18122     }
18123     else
18124 #endif
18125     test_paintingloop();
18126     cleanup_tests();
18127 }
18128 
18129 START_TEST(msg_input)
18130 {
18131     init_tests();
18132     test_accelerators();
18133     if (!pTrackMouseEvent)
18134         win_skip("TrackMouseEvent is not available\n");
18135     else
18136         test_TrackMouseEvent();
18137 
18138     test_keyflags();
18139     test_hotkey();
18140     cleanup_tests();
18141 }
18142 
18143 START_TEST(msg_timer)
18144 {
18145     init_tests();
18146     test_timers();
18147     test_timers_no_wnd();
18148     test_timers_exceptions();
18149     cleanup_tests();
18150 }
18151 
18152 typedef BOOL (WINAPI *IS_WINEVENT_HOOK_INSTALLED)(DWORD);
18153 
18154 START_TEST(msg_hook)
18155 {
18156 //    HMODULE user32 = GetModuleHandleA("user32.dll");
18157 //    IS_WINEVENT_HOOK_INSTALLED pIsWinEventHookInstalled = (IS_WINEVENT_HOOK_INSTALLED)GetProcAddress(user32, "IsWinEventHookInstalled");
18158     BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
18159 
18160     init_tests();
18161 
18162     if (pSetWinEventHook)
18163     {
18164         hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
18165                                        GetModuleHandleA(0), win_event_proc,
18166                                        0, GetCurrentThreadId(),
18167                                        WINEVENT_INCONTEXT);
18168         if (pIsWinEventHookInstalled && hEvent_hook)
18169         {
18170             UINT event;
18171             for (event = EVENT_MIN; event <= EVENT_MAX; event++)
18172                 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
18173         }
18174     }
18175     if (!hEvent_hook) win_skip( "no win event hook support\n" );
18176 
18177     test_winevents();
18178 
18179     /* Fix message sequences before removing 4 lines below */
18180     if (pUnhookWinEvent && hEvent_hook)
18181     {
18182         BOOL ret;
18183         ret = pUnhookWinEvent(hEvent_hook);
18184         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
18185         pUnhookWinEvent = 0;
18186     }
18187     hEvent_hook = 0;
18188     if (hCBT_hook)
18189     {
18190         test_set_hook();
18191         test_recursive_hook();
18192     }
18193     cleanup_tests();
18194 }
18195 
18196 START_TEST(msg_menu)
18197 {
18198     init_tests();
18199     test_sys_menu();
18200     test_menu_messages();
18201     test_TrackPopupMenu();
18202     test_TrackPopupMenuEmpty();
18203     cleanup_tests();
18204 }
18205 
18206 START_TEST(msg_mdi)
18207 {
18208     init_tests();
18209     test_mdi_messages();
18210     cleanup_tests();
18211 }
18212 
18213 START_TEST(msg_controls)
18214 {
18215     init_tests();
18216     test_button_messages();
18217     test_button_bm_get_set_image();
18218     test_autoradio_BM_CLICK();
18219     test_autoradio_kbd_move();
18220     test_static_messages();
18221     test_listbox_messages();
18222     test_combobox_messages();
18223     test_edit_messages();
18224     cleanup_tests();
18225 }
18226 
18227 START_TEST(msg_layered_window)
18228 {
18229     init_tests();
18230     test_layered_window();
18231     cleanup_tests();
18232 }
18233 
18234 START_TEST(msg_dialog)
18235 {
18236     init_tests();
18237     test_dialog_messages();
18238     test_EndDialog();
18239     cleanup_tests();
18240 }
18241 
18242 START_TEST(msg_clipboard)
18243 {
18244     init_tests();
18245     test_clipboard_viewers();
18246     cleanup_tests();
18247 }
18248