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 #ifndef __REACTOS__
24 #define _WIN32_WINNT 0x0600 /* For WM_CHANGEUISTATE,QS_RAWINPUT,WM_DWMxxxx */
25 #define WINVER 0x0600 /* for WM_GETTITLEBARINFOEX */
26 #endif
27 
28 #include <assert.h>
29 #include <limits.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 
33 #include "windef.h"
34 #include "winbase.h"
35 #include "wingdi.h"
36 #include "winuser.h"
37 #include "winnls.h"
38 #include "dbt.h"
39 
40 #include "wine/test.h"
41 
42 #define MDI_FIRST_CHILD_ID 2004
43 
44 /* undocumented SWP flags - from SDK 3.1 */
45 #define SWP_NOCLIENTSIZE	0x0800
46 #define SWP_NOCLIENTMOVE	0x1000
47 #define SWP_STATECHANGED	0x8000
48 
49 #define SW_NORMALNA	        0xCC    /* undoc. flag in MinMaximize */
50 
51 #ifndef WM_KEYF1
52 #define WM_KEYF1 0x004d
53 #endif
54 
55 #ifndef WM_SYSTIMER
56 #define WM_SYSTIMER	    0x0118
57 #endif
58 
59 #define WND_PARENT_ID		1
60 #define WND_POPUP_ID		2
61 #define WND_CHILD_ID		3
62 
63 #ifndef WM_LBTRACKPOINT
64 #define WM_LBTRACKPOINT  0x0131
65 #endif
66 
67 #ifdef __i386__
68 #define ARCH "x86"
69 #elif defined __x86_64__
70 #define ARCH "amd64"
71 #elif defined __arm__
72 #define ARCH "arm"
73 #elif defined __aarch64__
74 #define ARCH "arm64"
75 #else
76 #define ARCH "none"
77 #endif
78 
79 static BOOL   (WINAPI *pActivateActCtx)(HANDLE,ULONG_PTR*);
80 static HANDLE (WINAPI *pCreateActCtxW)(PCACTCTXW);
81 static BOOL   (WINAPI *pDeactivateActCtx)(DWORD,ULONG_PTR);
82 static BOOL   (WINAPI *pGetCurrentActCtx)(HANDLE *);
83 static BOOL   (WINAPI *pQueryActCtxW)(DWORD,HANDLE,void*,ULONG,void*,SIZE_T,SIZE_T*);
84 static void   (WINAPI *pReleaseActCtx)(HANDLE);
85 
86 /* encoded DRAWITEMSTRUCT into an LPARAM */
87 typedef struct
88 {
89     union
90     {
91         struct
92         {
93             UINT type    : 4;  /* ODT_* flags */
94             UINT ctl_id  : 4;  /* Control ID */
95             UINT item_id : 4;  /* Menu item ID */
96             UINT action  : 4;  /* ODA_* flags */
97             UINT state   : 16; /* ODS_* flags */
98         } item;
99         LPARAM lp;
100     } u;
101 } DRAW_ITEM_STRUCT;
102 
103 /* encoded MEASUREITEMSTRUCT into a WPARAM */
104 typedef struct
105 {
106     union
107     {
108         struct
109         {
110             UINT CtlType : 4;
111             UINT CtlID   : 4;
112             UINT itemID  : 4;
113             UINT wParam  : 20;
114         } item;
115         WPARAM wp;
116     } u;
117 } MEASURE_ITEM_STRUCT;
118 
119 static BOOL test_DestroyWindow_flag;
120 static HWINEVENTHOOK hEvent_hook;
121 static HHOOK hKBD_hook;
122 static HHOOK hCBT_hook;
123 static DWORD cbt_hook_thread_id;
124 
125 static const WCHAR testWindowClassW[] =
126 { 'T','e','s','t','W','i','n','d','o','w','C','l','a','s','s','W',0 };
127 
128 static LRESULT WINAPI ParentMsgCheckProcA(HWND, UINT, WPARAM, LPARAM);
129 
130 /*
131 FIXME: add tests for these
132 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
133  WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
134  WS_THICKFRAME: thick border
135  WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
136  WS_BORDER (default for overlapped windows): single black border
137  none (default for child (and popup?) windows): no border
138 */
139 
140 typedef enum {
141     sent=0x1,
142     posted=0x2,
143     parent=0x4,
144     wparam=0x8,
145     lparam=0x10,
146     defwinproc=0x20,
147     beginpaint=0x40,
148     optional=0x80,
149     hook=0x100,
150     winevent_hook=0x200,
151     kbd_hook=0x400
152 } msg_flags_t;
153 
154 struct message {
155     UINT message;          /* the WM_* code */
156     msg_flags_t flags;     /* message props */
157     WPARAM wParam;         /* expected value of wParam */
158     LPARAM lParam;         /* expected value of lParam */
159     WPARAM wp_mask;        /* mask for wParam checks */
160     LPARAM lp_mask;        /* mask for lParam checks */
161 };
162 
163 struct recvd_message {
164     UINT message;          /* the WM_* code */
165     msg_flags_t flags;     /* message props */
166     HWND hwnd;             /* window that received the message */
167     WPARAM wParam;         /* expected value of wParam */
168     LPARAM lParam;         /* expected value of lParam */
169     int line;              /* source line where logged */
170     const char *descr;     /* description for trace output */
171     char output[512];      /* trace output */
172 };
173 
174 /* Empty message sequence */
175 static const struct message WmEmptySeq[] =
176 {
177     { 0 }
178 };
179 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
180 static const struct message WmCreateOverlappedSeq[] = {
181     { HCBT_CREATEWND, hook },
182     { WM_GETMINMAXINFO, sent },
183     { WM_NCCREATE, sent },
184     { WM_NCCALCSIZE, sent|wparam, 0 },
185     { 0x0093, sent|defwinproc|optional },
186     { 0x0094, sent|defwinproc|optional },
187     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
188     { WM_CREATE, sent },
189     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
190     { 0 }
191 };
192 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
193  * for a not visible overlapped window.
194  */
195 static const struct message WmSWP_ShowOverlappedSeq[] = {
196     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
197     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
198     { WM_NCPAINT, sent|wparam|optional, 1 },
199     { WM_GETTEXT, sent|defwinproc|optional },
200     { WM_ERASEBKGND, sent|optional },
201     { HCBT_ACTIVATE, hook },
202     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
203     { WM_NOTIFYFORMAT, sent|optional },
204     { WM_QUERYUISTATE, sent|optional },
205     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
206     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
207     { WM_ACTIVATEAPP, sent|wparam, 1 },
208     { WM_NCACTIVATE, sent },
209     { WM_GETTEXT, sent|defwinproc|optional },
210     { WM_ACTIVATE, sent|wparam, 1 },
211     { HCBT_SETFOCUS, hook },
212     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
213     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
214     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
215     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
216     { WM_GETTEXT, sent|optional },
217     { WM_NCPAINT, sent|wparam|optional, 1 },
218     { WM_GETTEXT, sent|defwinproc|optional },
219     { WM_ERASEBKGND, sent|optional },
220     /* Win9x adds SWP_NOZORDER below */
221     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
222     { WM_GETTEXT, sent|optional },
223     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
224     { WM_NCPAINT, sent|wparam|optional, 1 },
225     { WM_ERASEBKGND, sent|optional },
226     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
227     { WM_SYNCPAINT, sent|optional },
228     { WM_GETTITLEBARINFOEX, sent|optional },
229     { WM_PAINT, sent|optional },
230     { WM_NCPAINT, sent|beginpaint|optional },
231     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
232     { WM_ERASEBKGND, sent|beginpaint|optional },
233     { 0 }
234 };
235 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
236  * for a visible overlapped window.
237  */
238 static const struct message WmSWP_HideOverlappedSeq[] = {
239     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
240     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
241     { HCBT_ACTIVATE, hook|optional },
242     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
243     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
244     { WM_NCACTIVATE, sent|optional },
245     { WM_ACTIVATE, sent|optional },
246     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
247     { 0 }
248 };
249 
250 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
251  * for a visible overlapped window.
252  */
253 static const struct message WmSWP_ResizeSeq[] = {
254     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
255     { WM_GETMINMAXINFO, sent|defwinproc },
256     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
257     { WM_NCPAINT, sent|optional },
258     { WM_GETTEXT, sent|defwinproc|optional },
259     { WM_ERASEBKGND, sent|optional },
260     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
261     { WM_SIZE, sent|defwinproc|optional },
262     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
263     { WM_NCPAINT, sent|optional },
264     { WM_GETTEXT, sent|defwinproc|optional },
265     { WM_ERASEBKGND, sent|optional },
266     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
267     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
268     { 0 }
269 };
270 
271 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
272  * for a visible popup window.
273  */
274 static const struct message WmSWP_ResizePopupSeq[] = {
275     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
276     { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* Win9x */
277     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
278     { WM_NCPAINT, sent|optional },
279     { WM_GETTEXT, sent|defwinproc|optional },
280     { WM_ERASEBKGND, sent|optional },
281     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
282     { WM_SIZE, sent|defwinproc|wparam|optional, SIZE_RESTORED },
283     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
284     { WM_NCPAINT, sent|optional },
285     { WM_GETTEXT, sent|defwinproc|optional },
286     { WM_ERASEBKGND, sent|optional },
287     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
288     { 0 }
289 };
290 
291 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE)
292  * for a visible overlapped window.
293  */
294 static const struct message WmSWP_MoveSeq[] = {
295     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE },
296     { WM_NCPAINT, sent|optional },
297     { WM_GETTEXT, sent|defwinproc|optional },
298     { WM_ERASEBKGND, sent|optional },
299     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
300     { WM_MOVE, sent|defwinproc|wparam, 0 },
301     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
302     { 0 }
303 };
304 /* Resize with SetWindowPos(SWP_NOZORDER)
305  * for a visible overlapped window
306  * SWP_NOZORDER is stripped by the logging code
307  */
308 static const struct message WmSWP_ResizeNoZOrder[] = {
309     { WM_WINDOWPOSCHANGING, sent|wparam, /*SWP_NOZORDER|*/SWP_NOACTIVATE },
310     { WM_GETMINMAXINFO, sent|defwinproc },
311     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
312     { WM_NCPAINT, sent|optional },
313     { WM_GETTEXT, sent|defwinproc|optional },
314     { WM_ERASEBKGND, sent|optional },
315     { WM_WINDOWPOSCHANGED, sent|wparam|optional, /*SWP_NOZORDER|*/SWP_NOACTIVATE, 0,
316       SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
317     { WM_MOVE, sent|defwinproc|optional },
318     { WM_SIZE, sent|defwinproc|optional },
319     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
320     { WM_NCPAINT, sent|optional }, /* Win9x doesn't send it */
321     { WM_GETTEXT, sent|defwinproc|optional }, /* Win9x doesn't send it */
322     { WM_ERASEBKGND, sent|optional }, /* Win9x doesn't send it */
323     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
324     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
325     { 0 }
326 };
327 
328 /* Switch visible mdi children */
329 static const struct message WmSwitchChild[] = {
330     /* Switch MDI child */
331     { WM_MDIACTIVATE, sent },/* in the MDI client */
332     { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 1st MDI child */
333     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
334     { WM_CHILDACTIVATE, sent },/* in the 1st MDI child */
335     /* Deactivate 2nd MDI child */
336     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
337     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
338     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
339     /* Preparing for maximize and maximize the 1st MDI child */
340     { WM_GETMINMAXINFO, sent|defwinproc }, /* in the 1st MDI child */
341     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED }, /* in the 1st MDI child */
342     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
343     { WM_CHILDACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
344     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 1st MDI child */
345     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, /* in the 1st MDI child */
346     /* Lock redraw 2nd MDI child */
347     { WM_SETREDRAW, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
348     { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
349     /* Restore 2nd MDI child */
350     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },/* in the 2nd MDI child */
351     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
352     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
353     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 2nd MDI child */
354     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, /* in the 2nd MDI child */
355     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
356     /* Redraw 2nd MDI child */
357     { WM_SETREDRAW, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
358     /* Redraw MDI frame */
359     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },/* in MDI frame */
360     { WM_NCCALCSIZE, sent|wparam, 1 },/* in MDI frame */
361     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in MDI frame */
362     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in MDI frame */
363     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
364     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
365     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
366     { HCBT_SETFOCUS, hook },
367     { WM_KILLFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
368     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },/* in the 1st MDI child */
369     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
370     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
371     { WM_SETFOCUS, sent },/* in the MDI client */
372     { HCBT_SETFOCUS, hook },
373     { WM_KILLFOCUS, sent },/* in the MDI client */
374     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
375     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, /* in the 1st MDI child */
376     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
377     { WM_SETFOCUS, sent|defwinproc }, /* in the 1st MDI child */
378     { WM_MDIACTIVATE, sent|defwinproc },/* in the 1st MDI child */
379     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* in the 1st MDI child */
380     { 0 }
381 };
382 
383 /* Switch visible not maximized mdi children */
384 static const struct message WmSwitchNotMaximizedChild[] = {
385     /* Switch not maximized MDI child */
386     { WM_MDIACTIVATE, sent },/* in the MDI client */
387     { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 2nd MDI child */
388     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
389     { WM_CHILDACTIVATE, sent },/* in the 2nd MDI child */
390     /* Deactivate 1st MDI child */
391     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
392     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
393     /* Activate 2nd MDI child */
394     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE}, /* in the 2nd MDI child */
395     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 2nd MDI child */
396     { HCBT_SETFOCUS, hook }, /* in the 1st MDI child */
397     { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
398     { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
399     { WM_IME_SETCONTEXT, sent|optional }, /* in the  MDI client */
400     { WM_SETFOCUS, sent, 0 }, /* in the  MDI client */
401     { HCBT_SETFOCUS, hook },
402     { WM_KILLFOCUS, sent }, /* in the  MDI client */
403     { WM_IME_SETCONTEXT, sent|optional }, /* in the  MDI client */
404     { WM_IME_SETCONTEXT, sent|defwinproc|optional  }, /* in the 1st MDI child */
405     { WM_SETFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
406     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
407     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in the 2nd MDI child */
408     { 0 }
409 };
410 
411 
412 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
413                 SWP_NOZORDER|SWP_FRAMECHANGED)
414  * for a visible overlapped window with WS_CLIPCHILDREN style set.
415  */
416 static const struct message WmSWP_FrameChanged_clip[] = {
417     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
418     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
419     { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
420     { WM_GETTEXT, sent|parent|defwinproc|optional },
421     { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
422     { WM_NCPAINT, sent }, /* wparam != 1 */
423     { WM_ERASEBKGND, sent },
424     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
425     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
426     { WM_PAINT, sent },
427     { 0 }
428 };
429 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|
430                 SWP_NOZORDER|SWP_FRAMECHANGED)
431  * for a visible overlapped window.
432  */
433 static const struct message WmSWP_FrameChangedDeferErase[] = {
434     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
435     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
436     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
437     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
438     { WM_PAINT, sent|parent|optional },
439     { WM_NCPAINT, sent|beginpaint|parent|optional }, /* wparam != 1 */
440     { WM_GETTEXT, sent|beginpaint|parent|defwinproc|optional },
441     { WM_PAINT, sent },
442     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
443     { WM_ERASEBKGND, sent|beginpaint|optional },
444     { 0 }
445 };
446 
447 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
448                 SWP_NOZORDER|SWP_FRAMECHANGED)
449  * for a visible overlapped window without WS_CLIPCHILDREN style set.
450  */
451 static const struct message WmSWP_FrameChanged_noclip[] = {
452     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
453     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
454     { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
455     { WM_GETTEXT, sent|parent|defwinproc|optional },
456     { WM_ERASEBKGND, sent|parent|optional },
457     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
458     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
459     { WM_PAINT, sent },
460     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
461     { WM_ERASEBKGND, sent|beginpaint|optional },
462     { 0 }
463 };
464 
465 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
466 static const struct message WmShowOverlappedSeq[] = {
467     { WM_SHOWWINDOW, sent|wparam, 1 },
468     { WM_NCPAINT, sent|wparam|optional, 1 },
469     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
470     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
471     { WM_NCPAINT, sent|wparam|optional, 1 },
472     { WM_GETTEXT, sent|defwinproc|optional },
473     { WM_ERASEBKGND, sent|optional },
474     { HCBT_ACTIVATE, hook|optional },
475     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
476     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
477     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
478     { WM_NCPAINT, sent|wparam|optional, 1 },
479     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
480     { WM_NCACTIVATE, sent|wparam|optional, 1 },
481     { WM_GETTEXT, sent|defwinproc|optional },
482     { WM_ACTIVATE, sent|wparam|optional, 1 },
483     { HCBT_SETFOCUS, hook|optional },
484     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
485     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
486     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
487     { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
488     { WM_GETTEXT, sent|optional },
489     { WM_NCPAINT, sent|wparam|optional, 1 },
490     { WM_GETTEXT, sent|defwinproc|optional },
491     { WM_ERASEBKGND, sent|optional },
492     /* Win9x adds SWP_NOZORDER below */
493     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
494     { WM_NCCALCSIZE, sent|optional },
495     { WM_GETTEXT, sent|optional },
496     { WM_NCPAINT, sent|optional },
497     { WM_ERASEBKGND, sent|optional },
498     { WM_SYNCPAINT, sent|optional },
499 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
500        * messages. Does that mean that CreateWindow doesn't set initial
501        * window dimensions for overlapped windows?
502        */
503     { WM_SIZE, sent },
504     { WM_MOVE, sent },
505 #endif
506     { WM_PAINT, sent|optional },
507     { WM_NCPAINT, sent|beginpaint|optional },
508     { 0 }
509 };
510 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible overlapped window */
511 static const struct message WmShowMaxOverlappedSeq[] = {
512     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
513     { WM_GETMINMAXINFO, sent },
514     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
515     { WM_GETMINMAXINFO, sent|defwinproc },
516     { WM_NCCALCSIZE, sent|wparam, TRUE },
517     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
518     { HCBT_ACTIVATE, hook|optional },
519     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
520     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
521     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
522     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
523     { WM_NCACTIVATE, sent|wparam|optional, 1 },
524     { WM_GETTEXT, sent|defwinproc|optional },
525     { WM_ACTIVATE, sent|wparam|optional, 1 },
526     { HCBT_SETFOCUS, hook|optional },
527     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
528     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
529     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
530     { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
531     { WM_GETTEXT, sent|optional },
532     { WM_NCPAINT, sent|wparam|optional, 1 },
533     { WM_GETTEXT, sent|defwinproc|optional },
534     { WM_ERASEBKGND, sent|optional },
535     /* Win9x adds SWP_NOZORDER below */
536     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
537     { WM_MOVE, sent|defwinproc },
538     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
539     { WM_GETTEXT, sent|optional },
540     { WM_NCCALCSIZE, sent|optional },
541     { WM_NCPAINT, sent|optional },
542     { WM_ERASEBKGND, sent|optional },
543     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
544     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
545     { WM_SYNCPAINT, sent|optional },
546     { WM_GETTITLEBARINFOEX, sent|optional },
547     { WM_PAINT, sent|optional },
548     { WM_NCPAINT, sent|beginpaint|optional },
549     { WM_ERASEBKGND, sent|beginpaint|optional },
550     { 0 }
551 };
552 /* ShowWindow(SW_RESTORE) for a not visible maximized overlapped window */
553 static const struct message WmShowRestoreMaxOverlappedSeq[] = {
554     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
555     { WM_GETTEXT, sent|optional },
556     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
557     { WM_GETMINMAXINFO, sent|defwinproc },
558     { WM_NCCALCSIZE, sent|wparam, TRUE },
559     { WM_NCPAINT, sent|optional },
560     { WM_GETTEXT, sent|defwinproc|optional },
561     { WM_ERASEBKGND, sent|optional },
562     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
563     { WM_MOVE, sent|defwinproc|optional },
564     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
565     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
566     { WM_NCPAINT, sent|optional },
567     { WM_ERASEBKGND, sent|optional },
568     { WM_PAINT, sent|optional },
569     { WM_GETTITLEBARINFOEX, sent|optional },
570     { WM_NCPAINT, sent|beginpaint|optional },
571     { WM_ERASEBKGND, sent|beginpaint|optional },
572     { 0 }
573 };
574 /* ShowWindow(SW_RESTORE) for a not visible minimized overlapped window */
575 static const struct message WmShowRestoreMinOverlappedSeq[] = {
576     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
577     { WM_QUERYOPEN, sent|optional },
578     { WM_GETTEXT, sent|optional },
579     { WM_NCACTIVATE, sent|wparam|optional, 1 },
580     { WM_WINDOWPOSCHANGING, sent|optional }, /* SWP_NOSIZE|SWP_NOMOVE */
581     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
582     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
583     { WM_MOVE, sent|optional },
584     { WM_SIZE, sent|wparam|optional, SIZE_RESTORED },
585     { WM_GETTEXT, sent|optional },
586     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED|SWP_NOCOPYBITS },
587     { WM_GETMINMAXINFO, sent|defwinproc|optional },
588     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
589     { HCBT_ACTIVATE, hook|optional },
590     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
591     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
592     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
593     { WM_NCACTIVATE, sent|wparam|optional, 1 },
594     { WM_GETTEXT, sent|defwinproc|optional },
595     { WM_ACTIVATE, sent|wparam|optional, 1 },
596     { HCBT_SETFOCUS, hook|optional },
597     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
598     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
599     { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
600     { WM_GETTEXT, sent|optional },
601     { WM_NCPAINT, sent|wparam|optional, 1 },
602     { WM_GETTEXT, sent|defwinproc|optional },
603     { WM_ERASEBKGND, sent },
604     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_STATECHANGED|SWP_FRAMECHANGED|SWP_NOCOPYBITS },
605     { WM_MOVE, sent|defwinproc },
606     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
607     { HCBT_SETFOCUS, hook|optional },
608     { WM_SETFOCUS, sent|wparam|optional, 0 },
609     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
610     { WM_NCPAINT, sent|wparam|optional, 1 },
611     { WM_ERASEBKGND, sent|optional },
612     { HCBT_SETFOCUS, hook|optional },
613     { WM_SETFOCUS, sent|wparam|optional, 0 },
614     { WM_ACTIVATE, sent|wparam, 1 },
615     { WM_GETTEXT, sent|optional },
616     { WM_PAINT, sent|optional },
617     { WM_GETTITLEBARINFOEX, sent|optional },
618     { WM_NCPAINT, sent|beginpaint|optional },
619     { WM_ERASEBKGND, sent|beginpaint|optional },
620     { 0 }
621 };
622 /* ShowWindow(SW_SHOWMINIMIZED) for a not visible overlapped window */
623 static const struct message WmShowMinOverlappedSeq[] = {
624     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
625     { HCBT_SETFOCUS, hook|optional },
626     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
627     { WM_KILLFOCUS, sent|optional },
628     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
629     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
630     { WM_GETTEXT, sent|optional },
631     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCOPYBITS|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
632     { WM_GETMINMAXINFO, sent|defwinproc },
633     { WM_NCCALCSIZE, sent|wparam, TRUE },
634     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
635     { WM_NCPAINT, sent|optional },
636     { WM_GETTEXT, sent|defwinproc|optional },
637     { WM_WINDOWPOSCHANGED, sent },
638     { WM_MOVE, sent|defwinproc },
639     { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
640     { WM_NCCALCSIZE, sent|optional },
641     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
642     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
643     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
644     { WM_NCACTIVATE, sent|wparam|optional, 0 },
645     { WM_GETTEXT, sent|defwinproc|optional },
646     { WM_ACTIVATE, sent|optional },
647     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
648 
649     /* Vista sometimes restores the window right away... */
650     { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
651     { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
652     { HCBT_MINMAX, hook|optional|lparam, 0, SW_RESTORE },
653     { WM_QUERYOPEN, sent|optional },
654     { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
655     { WM_GETMINMAXINFO, sent|optional|defwinproc },
656     { WM_NCCALCSIZE, sent|optional|wparam, TRUE },
657     { HCBT_ACTIVATE, hook|optional },
658     { WM_ACTIVATEAPP, sent|optional|wparam, 1 },
659     { WM_NCACTIVATE, sent|optional },
660     { WM_GETTEXT, sent|optional },
661     { WM_ACTIVATE, sent|optional|wparam, 1 },
662     { HCBT_SETFOCUS, hook|optional },
663     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
664     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
665     { WM_SETFOCUS, sent|optional },
666     { WM_NCPAINT, sent|optional },
667     { WM_GETTEXT, sent|defwinproc|optional },
668     { WM_ERASEBKGND, sent|optional },
669     { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
670     { WM_MOVE, sent|defwinproc|optional },
671     { WM_SIZE, sent|defwinproc|optional|wparam, SIZE_RESTORED },
672     { WM_ACTIVATE, sent|optional|wparam, 1 },
673     { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
674     { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
675 
676     { WM_PAINT, sent|optional },
677     { WM_NCPAINT, sent|beginpaint|optional },
678     { WM_ERASEBKGND, sent|beginpaint|optional },
679     { 0 }
680 };
681 /* ShowWindow(SW_HIDE) for a visible overlapped window */
682 static const struct message WmHideOverlappedSeq[] = {
683     { WM_SHOWWINDOW, sent|wparam, 0 },
684     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
685     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
686     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
687     { WM_SIZE, sent|optional }, /* XP doesn't send it */
688     { WM_MOVE, sent|optional }, /* XP doesn't send it */
689     { WM_NCACTIVATE, sent|wparam|optional, 0 },
690     { WM_ACTIVATE, sent|wparam|optional, 0 },
691     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
692     { HCBT_SETFOCUS, hook|optional },
693     { WM_KILLFOCUS, sent|wparam|optional, 0 },
694     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
695     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
696     { 0 }
697 };
698 /* DestroyWindow for a visible overlapped window */
699 static const struct message WmDestroyOverlappedSeq[] = {
700     { HCBT_DESTROYWND, hook },
701     { 0x0090, sent|optional },
702     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
703     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
704     { 0x0090, sent|optional },
705     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
706     { WM_NCACTIVATE, sent|optional|wparam, 0 },
707     { WM_ACTIVATE, sent|optional },
708     { WM_ACTIVATEAPP, sent|optional|wparam, 0 },
709     { WM_KILLFOCUS, sent|optional|wparam, 0 },
710     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
711     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
712     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
713     { WM_DESTROY, sent },
714     { WM_NCDESTROY, sent },
715     { 0 }
716 };
717 /* CreateWindow(WS_MAXIMIZE|WS_VISIBLE) for popup window */
718 static const struct message WmCreateMaxPopupSeq[] = {
719     { HCBT_CREATEWND, hook },
720     { WM_NCCREATE, sent },
721     { WM_NCCALCSIZE, sent|wparam, 0 },
722     { WM_CREATE, sent },
723     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
724     { WM_SIZE, sent|wparam, SIZE_RESTORED },
725     { WM_MOVE, sent },
726     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
727     { WM_GETMINMAXINFO, sent },
728     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
729     { WM_NCCALCSIZE, sent|wparam, TRUE },
730     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
731     { WM_MOVE, sent|defwinproc },
732     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
733     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
734     { WM_SHOWWINDOW, sent|wparam, 1 },
735     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
736     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
737     { HCBT_ACTIVATE, hook },
738     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
739     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
740     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
741     { WM_NCPAINT, sent|wparam|optional, 1 },
742     { WM_ERASEBKGND, sent|optional },
743     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_NOMOVE|SWP_NOSIZE },
744     { WM_ACTIVATEAPP, sent|wparam, 1 },
745     { WM_NCACTIVATE, sent },
746     { WM_ACTIVATE, sent|wparam, 1 },
747     { HCBT_SETFOCUS, hook },
748     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
749     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
750     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
751     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
752     { WM_GETTEXT, sent|optional },
753     { WM_SYNCPAINT, sent|wparam|optional, 4 },
754     { WM_NCPAINT, sent|wparam|optional, 1 },
755     { WM_ERASEBKGND, sent|optional },
756     { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
757     { WM_ERASEBKGND, sent|defwinproc|optional },
758     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
759     { 0 }
760 };
761 /* CreateWindow(WS_MAXIMIZE) for popup window, not initially visible */
762 static const struct message WmCreateInvisibleMaxPopupSeq[] = {
763     { HCBT_CREATEWND, hook },
764     { WM_NCCREATE, sent },
765     { WM_NCCALCSIZE, sent|wparam, 0 },
766     { WM_CREATE, sent },
767     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
768     { WM_SIZE, sent|wparam, SIZE_RESTORED },
769     { WM_MOVE, sent },
770     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
771     { WM_GETMINMAXINFO, sent },
772     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED  },
773     { WM_NCCALCSIZE, sent|wparam, TRUE },
774     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
775     { WM_MOVE, sent|defwinproc },
776     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
777     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
778     { 0 }
779 };
780 /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */
781 static const struct message WmShowMaxPopupResizedSeq_todo[] = {
782     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
783     { WM_GETMINMAXINFO, sent },
784     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
785     { WM_NCCALCSIZE, sent|wparam, TRUE },
786     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
787     { HCBT_ACTIVATE, hook },
788     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
789     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
790     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
791     { WM_NCPAINT, sent|wparam|optional, 1 },
792     { WM_ERASEBKGND, sent|optional },
793     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
794     { WM_ACTIVATEAPP, sent|wparam, 1 },
795     { WM_NCACTIVATE, sent },
796     { WM_ACTIVATE, sent|wparam, 1 },
797     { HCBT_SETFOCUS, hook },
798     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
799     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
800     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
801     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
802     { WM_GETTEXT, sent|optional },
803     { WM_NCPAINT, sent|wparam|optional, 1 },
804     { WM_ERASEBKGND, sent|optional },
805     { WM_WINDOWPOSCHANGED, sent },
806     /* WinNT4.0 sends WM_MOVE */
807     { WM_MOVE, sent|defwinproc|optional },
808     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
809     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
810     { 0 }
811 };
812 static const struct message WmShowMaxPopupResizedSeq[] = {
813     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
814     { WM_GETMINMAXINFO, sent },
815     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
816     { WM_NCCALCSIZE, sent|wparam, TRUE },
817     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
818     { HCBT_ACTIVATE, hook },
819     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
820     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
821     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
822     { WM_NCPAINT, sent|wparam|optional, 1 },
823     { WM_ERASEBKGND, sent|optional },
824     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
825     { WM_ACTIVATEAPP, sent|wparam, 1 },
826     { WM_NCACTIVATE, sent },
827     { WM_ACTIVATE, sent|wparam, 1 },
828     { HCBT_SETFOCUS, hook },
829     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
830     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
831     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
832     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
833     { WM_GETTEXT, sent|optional },
834     { WM_NCPAINT, sent|optional }, /* We'll check WM_NCPAINT behaviour in another test */
835     { WM_ERASEBKGND, sent|optional },
836     { WM_WINDOWPOSCHANGED, sent },
837     /* WinNT4.0 sends WM_MOVE */
838     { WM_MOVE, sent|defwinproc|optional },
839     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
840     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
841     { 0 }
842 };
843 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible popup window */
844 static const struct message WmShowMaxPopupSeq[] = {
845     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
846     { WM_GETMINMAXINFO, sent },
847     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
848     { WM_NCCALCSIZE, sent|wparam, TRUE },
849     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
850     { HCBT_ACTIVATE, hook },
851     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
852     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
853     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
854     { WM_NCPAINT, sent|wparam|optional, 1 },
855     { WM_ERASEBKGND, sent|optional },
856     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOMOVE|SWP_NOSIZE },
857     { WM_ACTIVATEAPP, sent|wparam, 1 },
858     { WM_NCACTIVATE, sent },
859     { WM_ACTIVATE, sent|wparam, 1 },
860     { HCBT_SETFOCUS, hook },
861     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
862     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
863     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
864     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
865     { WM_GETTEXT, sent|optional },
866     { WM_SYNCPAINT, sent|wparam|optional, 4 },
867     { WM_NCPAINT, sent|wparam|optional, 1 },
868     { WM_ERASEBKGND, sent|optional },
869     { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
870     { WM_ERASEBKGND, sent|defwinproc|optional },
871     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE },
872     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
873     { 0 }
874 };
875 /* CreateWindow(WS_VISIBLE) for popup window */
876 static const struct message WmCreatePopupSeq[] = {
877     { HCBT_CREATEWND, hook },
878     { WM_NCCREATE, sent },
879     { WM_NCCALCSIZE, sent|wparam, 0 },
880     { WM_CREATE, sent },
881     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
882     { WM_SIZE, sent|wparam, SIZE_RESTORED },
883     { WM_MOVE, sent },
884     { WM_SHOWWINDOW, sent|wparam, 1 },
885     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
886     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
887     { HCBT_ACTIVATE, hook },
888     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
889     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
890     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
891     { WM_NCPAINT, sent|wparam|optional, 1 },
892     { WM_ERASEBKGND, sent|optional },
893     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
894     { WM_ACTIVATEAPP, sent|wparam, 1 },
895     { WM_NCACTIVATE, sent },
896     { WM_ACTIVATE, sent|wparam, 1 },
897     { HCBT_SETFOCUS, hook },
898     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
899     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
900     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
901     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
902     { WM_GETTEXT, sent|optional },
903     { WM_SYNCPAINT, sent|wparam|optional, 4 },
904     { WM_NCPAINT, sent|wparam|optional, 1 },
905     { WM_ERASEBKGND, sent|optional },
906     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
907     { 0 }
908 };
909 /* ShowWindow(SW_SHOWMAXIMIZED) for a visible popup window */
910 static const struct message WmShowVisMaxPopupSeq[] = {
911     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
912     { WM_GETMINMAXINFO, sent },
913     { WM_GETTEXT, sent|optional },
914     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
915     { WM_GETTEXT, sent|optional },
916     { WM_NCCALCSIZE, sent|wparam, TRUE },
917     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
918     { WM_NCPAINT, sent|wparam|optional, 1 },
919     { WM_ERASEBKGND, sent|optional },
920     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
921     { WM_MOVE, sent|defwinproc },
922     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
923     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
924     { 0 }
925 };
926 /* CreateWindow (for a child popup window, not initially visible) */
927 static const struct message WmCreateChildPopupSeq[] = {
928     { HCBT_CREATEWND, hook },
929     { WM_NCCREATE, sent },
930     { WM_NCCALCSIZE, sent|wparam, 0 },
931     { WM_CREATE, sent },
932     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
933     { WM_SIZE, sent|wparam, SIZE_RESTORED },
934     { WM_MOVE, sent },
935     { 0 }
936 };
937 /* CreateWindow (for a popup window, not initially visible,
938  * which sets WS_VISIBLE in WM_CREATE handler)
939  */
940 static const struct message WmCreateInvisiblePopupSeq[] = {
941     { HCBT_CREATEWND, hook },
942     { WM_NCCREATE, sent },
943     { WM_NCCALCSIZE, sent|wparam, 0 },
944     { WM_CREATE, sent },
945     { WM_STYLECHANGING, sent },
946     { WM_STYLECHANGED, sent },
947     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
948     { WM_SIZE, sent|wparam, SIZE_RESTORED },
949     { WM_MOVE, sent },
950     { 0 }
951 };
952 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
953  * for a popup window with WS_VISIBLE style set
954  */
955 static const struct message WmShowVisiblePopupSeq_2[] = {
956     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
957     { 0 }
958 };
959 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
960  * for a popup window with WS_VISIBLE style set
961  */
962 static const struct message WmShowVisiblePopupSeq_3[] = {
963     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
964     { HCBT_ACTIVATE, hook },
965     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
966     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
967     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
968     { WM_NCACTIVATE, sent },
969     { WM_ACTIVATE, sent|wparam, 1 },
970     { HCBT_SETFOCUS, hook },
971     { WM_KILLFOCUS, sent|parent },
972     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
973     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
974     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
975     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
976     { WM_SETFOCUS, sent|defwinproc },
977     { WM_GETTEXT, sent|optional },
978     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_SHOWWINDOW },
979     { 0 }
980 };
981 /* CreateWindow (for a popup window with WS_VISIBLE style set and extreme location)
982  */
983 static const struct message WmShowPopupExtremeLocationSeq[] = {
984     { HCBT_CREATEWND, hook },
985     { WM_NCCREATE, sent },
986     { WM_NCCALCSIZE, sent|wparam, 0 },
987     { WM_CREATE, sent },
988     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
989     { WM_SIZE, sent|wparam, SIZE_RESTORED },
990     { WM_MOVE, sent },
991     { WM_SHOWWINDOW, sent|wparam, 1 },
992     { WM_WINDOWPOSCHANGING, sent },
993     { HCBT_ACTIVATE, hook },
994     { WM_WINDOWPOSCHANGING, sent|optional },
995     { WM_QUERYNEWPALETTE, sent|optional },
996     { WM_ACTIVATEAPP, sent },
997     { WM_NCACTIVATE, sent },
998     { WM_ACTIVATE, sent },
999     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1000     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1001     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1002     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1003     { HCBT_SETFOCUS, hook },
1004     { WM_SETFOCUS, sent|defwinproc },
1005     { WM_NCPAINT, sent|wparam, 1 },
1006     { WM_ERASEBKGND, sent },
1007     { WM_WINDOWPOSCHANGED, sent },
1008     /* occasionally received on test machines */
1009     { WM_NCPAINT, sent|optional },
1010     { WM_ERASEBKGND, sent|optional },
1011     { 0 }
1012 };
1013 /* CreateWindow (for a popup window with WS_VISIBLE style set)
1014  */
1015 static const struct message WmShowPopupFirstDrawSeq_1[] = {
1016     { HCBT_CREATEWND, hook },
1017     { WM_NCCREATE, sent },
1018     { WM_NCCALCSIZE, sent|wparam, 0 },
1019     { WM_CREATE, sent },
1020     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1021     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1022     { WM_MOVE, sent },
1023     { WM_SHOWWINDOW, sent|wparam, 1 },
1024     { WM_WINDOWPOSCHANGING, sent },
1025     { HCBT_ACTIVATE, hook },
1026     { WM_WINDOWPOSCHANGING, sent|optional },
1027     { WM_QUERYNEWPALETTE, sent|optional },
1028     { WM_ACTIVATEAPP, sent },
1029     { WM_NCACTIVATE, sent },
1030     { WM_ACTIVATE, sent },
1031     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1032     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1033     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1034     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1035     { HCBT_SETFOCUS, hook },
1036     { WM_SETFOCUS, sent|defwinproc },
1037     { WM_NCPAINT, sent|wparam, 1 },
1038     { WM_ERASEBKGND, sent },
1039     { WM_WINDOWPOSCHANGED, sent },
1040     { WM_PAINT, sent },
1041     /* occasionally received on test machines */
1042     { WM_NCPAINT, sent|beginpaint|optional },
1043     { WM_ERASEBKGND, sent|beginpaint|optional },
1044     { 0 }
1045 };
1046 /* CreateWindow (for a popup window that is shown with ShowWindow(SW_SHOWMAXIMIZED))
1047  */
1048 static const struct message WmShowPopupFirstDrawSeq_2[] = {
1049     { HCBT_CREATEWND, hook },
1050     { WM_NCCREATE, sent },
1051     { WM_NCCALCSIZE, sent|wparam, 0 },
1052     { WM_CREATE, sent },
1053     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1054     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1055     { WM_MOVE, sent },
1056     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1057     { WM_GETMINMAXINFO, sent },
1058     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_STATECHANGED|SWP_SHOWWINDOW|SWP_FRAMECHANGED  },
1059     { WM_NCCALCSIZE, sent|wparam, TRUE },
1060     { HCBT_ACTIVATE, hook },
1061     { WM_WINDOWPOSCHANGING, sent|optional },
1062     { WM_NCPAINT, sent|optional|wparam, 1 },
1063     { WM_ERASEBKGND, sent|optional },
1064     { WM_WINDOWPOSCHANGED, sent|optional },
1065     { WM_QUERYNEWPALETTE, sent|optional },
1066     { WM_ACTIVATEAPP, sent },
1067     { WM_NCACTIVATE, sent },
1068     { WM_ACTIVATE, sent },
1069     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1070     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1071     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1072     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1073     { HCBT_SETFOCUS, hook },
1074     { WM_SETFOCUS, sent|defwinproc },
1075     { WM_NCPAINT, sent|wparam, 1 },
1076     { WM_ERASEBKGND, sent },
1077     { WM_WINDOWPOSCHANGED, sent|optional },
1078     { WM_MOVE, sent|defwinproc },
1079     { WM_SIZE, sent|defwinproc, 0 },
1080     { WM_PAINT, sent},
1081     /* occasionally received on test machines */
1082     { WM_NCPAINT, sent|beginpaint|optional },
1083     { WM_ERASEBKGND, sent|beginpaint|optional },
1084     { 0 }
1085 };
1086 static const struct message WmFirstDrawSetWindowPosSeq1[] = {
1087     { HCBT_CREATEWND, hook },
1088     { WM_NCCREATE, sent },
1089     { WM_NCCALCSIZE, sent|wparam, 0 },
1090     { WM_CREATE, sent },
1091     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1092     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1093     { WM_MOVE, sent },
1094     { WM_WINDOWPOSCHANGING, sent },
1095     { HCBT_ACTIVATE, hook },
1096     { WM_WINDOWPOSCHANGING, sent|optional },
1097     { WM_QUERYNEWPALETTE, sent|optional },
1098     { WM_ACTIVATEAPP, sent },
1099     { WM_NCACTIVATE, sent },
1100     { WM_ACTIVATE, sent },
1101     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1102     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1103     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1104     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1105     { HCBT_SETFOCUS, hook },
1106     { WM_SETFOCUS, sent|defwinproc },
1107     { WM_NCPAINT, sent|wparam, 1 },
1108     { WM_ERASEBKGND, sent },
1109     { WM_WINDOWPOSCHANGED, sent },
1110     { WM_MOVE, sent|defwinproc },
1111     { 0 }
1112 };
1113 static const struct message WmFirstDrawSetWindowPosSeq2[] = {
1114     { HCBT_CREATEWND, hook },
1115     { WM_NCCREATE, sent },
1116     { WM_NCCALCSIZE, sent|wparam, 0 },
1117     { WM_CREATE, sent },
1118     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1119     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1120     { WM_MOVE, sent },
1121     { WM_WINDOWPOSCHANGING, sent },
1122     { HCBT_ACTIVATE, hook },
1123     { WM_QUERYNEWPALETTE, sent|optional },
1124     { WM_WINDOWPOSCHANGING, sent|optional },
1125     { WM_ACTIVATEAPP, sent },
1126     { WM_NCACTIVATE, sent },
1127     { WM_ACTIVATE, sent },
1128     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1129     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1130     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1131     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1132     { HCBT_SETFOCUS, hook },
1133     { WM_SETFOCUS, sent|defwinproc },
1134     { WM_WINDOWPOSCHANGED, sent },
1135     { WM_MOVE, sent|defwinproc },
1136     { 0 }
1137 };
1138 static const struct message WmFirstDrawSetWindowPosSeq3[] = {
1139     { HCBT_CREATEWND, hook },
1140     { WM_NCCREATE, sent },
1141     { WM_NCCALCSIZE, sent|wparam, 0 },
1142     { WM_CREATE, sent },
1143     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1144     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1145     { WM_MOVE, sent },
1146     { HCBT_ACTIVATE, hook|optional },
1147     /* Probably shouldn't happen, but not part of this test */
1148     { WM_QUERYNEWPALETTE, sent|optional },
1149     { WM_ACTIVATEAPP, sent|optional },
1150     { WM_NCACTIVATE, sent|optional },
1151     { WM_ACTIVATE, sent|optional },
1152     { HCBT_SETFOCUS, hook|optional },
1153     { WM_SETFOCUS, sent|defwinproc|optional },
1154     { 0 }
1155 };
1156 static const struct message WmFirstDrawSetWindowPosSeq4[] = {
1157     { HCBT_CREATEWND, hook },
1158     { WM_NCCREATE, sent },
1159     { WM_NCCALCSIZE, sent|wparam, 0 },
1160     { WM_CREATE, sent },
1161     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1162     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1163     { WM_MOVE, sent },
1164     { WM_WINDOWPOSCHANGING, sent },
1165     { HCBT_ACTIVATE, hook },
1166     { WM_WINDOWPOSCHANGING, sent|optional },
1167     { WM_QUERYNEWPALETTE, sent|optional },
1168     { WM_ACTIVATEAPP, sent },
1169     { WM_NCACTIVATE, sent },
1170     { WM_ACTIVATE, sent },
1171     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1172     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1173     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1174     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1175     { HCBT_SETFOCUS, hook },
1176     { WM_SETFOCUS, sent|defwinproc },
1177     { WM_NCPAINT, sent|wparam, 1 },
1178     { WM_ERASEBKGND, sent },
1179     { WM_WINDOWPOSCHANGED, sent },
1180     { 0 }
1181 };
1182 static const struct message WmFirstDrawSetWindowPosSeq5[] = {
1183     { HCBT_CREATEWND, hook },
1184     { WM_NCCREATE, sent },
1185     { WM_NCCALCSIZE, sent|wparam, 0 },
1186     { WM_CREATE, sent },
1187     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1188     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1189     { WM_MOVE, sent },
1190     { WM_WINDOWPOSCHANGING, sent },
1191     { HCBT_ACTIVATE, hook },
1192     { WM_WINDOWPOSCHANGING, sent|optional },
1193     { WM_QUERYNEWPALETTE, sent|optional },
1194     { WM_ACTIVATEAPP, sent },
1195     { WM_NCACTIVATE, sent },
1196     { WM_ACTIVATE, sent },
1197     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1198     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1199     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1200     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1201     { HCBT_SETFOCUS, hook },
1202     { WM_SETFOCUS, sent|defwinproc },
1203     { WM_WINDOWPOSCHANGED, sent },
1204     { 0 }
1205 };
1206 static const struct message WmFirstDrawChildSeq1[] = {
1207     { 0 }
1208 };
1209 static const struct message WmFirstDrawChildSeq2[] = {
1210     { WM_NCPAINT, sent|wparam, 1 },
1211     { WM_ERASEBKGND, sent },
1212     /* occasionally received on test machines */
1213     { WM_NCPAINT, sent|optional },
1214     { WM_ERASEBKGND, sent|optional },
1215     { 0 }
1216 };
1217 /* CreateWindow (for child window, not initially visible) */
1218 static const struct message WmCreateChildSeq[] = {
1219     { HCBT_CREATEWND, hook },
1220     { WM_NCCREATE, sent },
1221     /* child is inserted into parent's child list after WM_NCCREATE returns */
1222     { WM_NCCALCSIZE, sent|wparam, 0 },
1223     { WM_CREATE, sent },
1224     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1225     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1226     { WM_MOVE, sent },
1227     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1228     { 0 }
1229 };
1230 /* CreateWindow (for maximized child window, not initially visible) */
1231 static const struct message WmCreateMaximizedChildSeq[] = {
1232     { HCBT_CREATEWND, hook },
1233     { WM_NCCREATE, sent },
1234     { WM_NCCALCSIZE, sent|wparam, 0 },
1235     { WM_CREATE, sent },
1236     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1237     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1238     { WM_MOVE, sent },
1239     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1240     { WM_GETMINMAXINFO, sent },
1241     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
1242     { WM_NCCALCSIZE, sent|wparam, 1 },
1243     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1244     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1245     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1246     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1247     { 0 }
1248 };
1249 /* CreateWindow (for a child window, initially visible) */
1250 static const struct message WmCreateVisibleChildSeq[] = {
1251     { HCBT_CREATEWND, hook },
1252     { WM_NCCREATE, sent },
1253     /* child is inserted into parent's child list after WM_NCCREATE returns */
1254     { WM_NCCALCSIZE, sent|wparam, 0 },
1255     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1256     { WM_CREATE, sent },
1257     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1258     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1259     { WM_MOVE, sent },
1260     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1261     { WM_SHOWWINDOW, sent|wparam, 1 },
1262     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1263     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1264     { WM_ERASEBKGND, sent|parent|optional },
1265     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1266     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */
1267     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1268     { 0 }
1269 };
1270 /* ShowWindow(SW_SHOW) for a not visible child window */
1271 static const struct message WmShowChildSeq[] = {
1272     { WM_SHOWWINDOW, sent|wparam, 1 },
1273     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1274     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1275     { WM_ERASEBKGND, sent|parent|optional },
1276     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1277     { 0 }
1278 };
1279 /* ShowWindow(SW_HIDE) for a visible child window */
1280 static const struct message WmHideChildSeq[] = {
1281     { WM_SHOWWINDOW, sent|wparam, 0 },
1282     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1283     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1284     { WM_ERASEBKGND, sent|parent|optional },
1285     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1286     { 0 }
1287 };
1288 /* ShowWindow(SW_HIDE) for a visible child window checking all parent events*/
1289 static const struct message WmHideChildSeq2[] = {
1290     { WM_SHOWWINDOW, sent|wparam, 0 },
1291     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1292     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1293     { WM_ERASEBKGND, sent|parent|optional },
1294     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1295     { 0 }
1296 };
1297 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
1298  * for a not visible child window
1299  */
1300 static const struct message WmShowChildSeq_2[] = {
1301     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1302     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1303     { WM_CHILDACTIVATE, sent },
1304     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1305     { 0 }
1306 };
1307 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
1308  * for a not visible child window
1309  */
1310 static const struct message WmShowChildSeq_3[] = {
1311     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1312     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1313     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1314     { 0 }
1315 };
1316 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
1317  * for a visible child window with a caption
1318  */
1319 static const struct message WmShowChildSeq_4[] = {
1320     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1321     { WM_CHILDACTIVATE, sent },
1322     { 0 }
1323 };
1324 /* ShowWindow(SW_MINIMIZE) for child with invisible parent */
1325 static const struct message WmShowChildInvisibleParentSeq_1[] = {
1326     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1327     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1328     { WM_NCCALCSIZE, sent|wparam, 1 },
1329     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1330     { WM_CHILDACTIVATE, sent|optional },
1331     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1332     { WM_MOVE, sent|defwinproc },
1333     { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1334     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1335     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1336     /* FIXME: Wine creates an icon/title window while Windows doesn't */
1337     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1338     { WM_GETTEXT, sent|optional },
1339     { 0 }
1340 };
1341 /* repeated ShowWindow(SW_MINIMIZE) for child with invisible parent */
1342 static const struct message WmShowChildInvisibleParentSeq_1r[] = {
1343     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1344     { 0 }
1345 };
1346 /* ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1347 static const struct message WmShowChildInvisibleParentSeq_2[] = {
1348     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1349     { WM_GETMINMAXINFO, sent },
1350     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
1351     { WM_NCCALCSIZE, sent|wparam, 1 },
1352     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1353     { WM_CHILDACTIVATE, sent },
1354     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1355     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1356     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1357     { 0 }
1358 };
1359 /* repeated ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1360 static const struct message WmShowChildInvisibleParentSeq_2r[] = {
1361     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1362     { 0 }
1363 };
1364 /* ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1365 static const struct message WmShowChildInvisibleParentSeq_3[] = {
1366     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1367     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1368     { WM_NCCALCSIZE, sent|wparam, 1 },
1369     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1370     { WM_CHILDACTIVATE, sent },
1371     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1372     { WM_MOVE, sent|defwinproc },
1373     { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1374     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1375     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1376     /* FIXME: Wine creates an icon/title window while Windows doesn't */
1377     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1378     { WM_GETTEXT, sent|optional },
1379     { 0 }
1380 };
1381 /* repeated ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1382 static const struct message WmShowChildInvisibleParentSeq_3r[] = {
1383     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1384     { 0 }
1385 };
1386 /* ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1387 static const struct message WmShowChildInvisibleParentSeq_4[] = {
1388     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1389     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
1390     { WM_NCCALCSIZE, sent|wparam, 1 },
1391     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1392     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1393     { WM_MOVE, sent|defwinproc },
1394     { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1395     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1396     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1397     /* FIXME: Wine creates an icon/title window while Windows doesn't */
1398     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1399     { WM_GETTEXT, sent|optional },
1400     { 0 }
1401 };
1402 /* repeated ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1403 static const struct message WmShowChildInvisibleParentSeq_4r[] = {
1404     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1405     { 0 }
1406 };
1407 /* ShowWindow(SW_SHOW) for child with invisible parent */
1408 static const struct message WmShowChildInvisibleParentSeq_5[] = {
1409     { WM_SHOWWINDOW, sent|wparam, 1 },
1410     { 0 }
1411 };
1412 /* ShowWindow(SW_HIDE) for child with invisible parent */
1413 static const struct message WmHideChildInvisibleParentSeq[] = {
1414     { WM_SHOWWINDOW, sent|wparam, 0 },
1415     { 0 }
1416 };
1417 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
1418 static const struct message WmShowChildInvisibleParentSeq_6[] = {
1419     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1420     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1421     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1422     { 0 }
1423 };
1424 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
1425 static const struct message WmHideChildInvisibleParentSeq_2[] = {
1426     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1427     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1428     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1429     { 0 }
1430 };
1431 /* DestroyWindow for a visible child window */
1432 static const struct message WmDestroyChildSeq[] = {
1433     { HCBT_DESTROYWND, hook },
1434     { 0x0090, sent|optional },
1435     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1436     { WM_SHOWWINDOW, sent|wparam, 0 },
1437     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1438     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1439     { WM_ERASEBKGND, sent|parent|optional },
1440     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1441     { HCBT_SETFOCUS, hook }, /* set focus to a parent */
1442     { WM_KILLFOCUS, sent },
1443     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1444     { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
1445     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1446     { WM_SETFOCUS, sent|parent },
1447     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1448     { WM_DESTROY, sent },
1449     { WM_DESTROY, sent|optional }, /* some other (IME?) window */
1450     { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
1451     { WM_NCDESTROY, sent },
1452     { 0 }
1453 };
1454 /* visible child window destroyed by thread exit */
1455 static const struct message WmExitThreadSeq[] = {
1456     { WM_NCDESTROY, sent },  /* actually in grandchild */
1457     { WM_PAINT, sent|parent },
1458     { WM_ERASEBKGND, sent|parent|beginpaint },
1459     { 0 }
1460 };
1461 /* DestroyWindow for a visible child window with invisible parent */
1462 static const struct message WmDestroyInvisibleChildSeq[] = {
1463     { HCBT_DESTROYWND, hook },
1464     { 0x0090, sent|optional },
1465     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1466     { WM_SHOWWINDOW, sent|wparam, 0 },
1467     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1468     { WM_DESTROY, sent },
1469     { WM_NCDESTROY, sent },
1470     { 0 }
1471 };
1472 /* Resizing child window with MoveWindow (32) */
1473 static const struct message WmResizingChildWithMoveWindowSeq[] = {
1474     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
1475     { WM_NCCALCSIZE, sent|wparam, 1 },
1476     { WM_ERASEBKGND, sent|parent|optional },
1477     { WM_ERASEBKGND, sent|optional },
1478     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE },
1479     { WM_MOVE, sent|defwinproc },
1480     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1481     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1482     { 0 }
1483 };
1484 /* Creation of a custom dialog (32) */
1485 static const struct message WmCreateCustomDialogSeq[] = {
1486     { HCBT_CREATEWND, hook },
1487     { WM_GETMINMAXINFO, sent },
1488     { WM_NCCREATE, sent },
1489     { WM_NCCALCSIZE, sent|wparam, 0 },
1490     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1491     { WM_CREATE, sent },
1492     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1493     { WM_NOTIFYFORMAT, sent|optional },
1494     { WM_QUERYUISTATE, sent|optional },
1495     { WM_WINDOWPOSCHANGING, sent|optional },
1496     { WM_GETMINMAXINFO, sent|optional },
1497     { WM_NCCALCSIZE, sent|optional },
1498     { WM_WINDOWPOSCHANGED, sent|optional },
1499     { WM_SHOWWINDOW, sent|wparam, 1 },
1500     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1501     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1502     { HCBT_ACTIVATE, hook },
1503     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1504 
1505 
1506     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1507 
1508     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1509 
1510     { WM_NCACTIVATE, sent },
1511     { WM_GETTEXT, sent|optional|defwinproc },
1512     { WM_GETTEXT, sent|optional|defwinproc },
1513     { WM_GETTEXT, sent|optional|defwinproc },
1514     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
1515     { WM_ACTIVATE, sent|wparam, 1 },
1516     { WM_GETTEXT, sent|optional },
1517     { WM_KILLFOCUS, sent|parent },
1518     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1519     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1520     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1521     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1522     { WM_SETFOCUS, sent },
1523     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1524     { WM_NCPAINT, sent|wparam, 1 },
1525     { WM_GETTEXT, sent|optional|defwinproc },
1526     { WM_GETTEXT, sent|optional|defwinproc },
1527     { WM_ERASEBKGND, sent },
1528     { WM_CTLCOLORDLG, sent|optional|defwinproc },
1529     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1530     { WM_GETTEXT, sent|optional },
1531     { WM_GETTEXT, sent|optional },
1532     { WM_NCCALCSIZE, sent|optional },
1533     { WM_NCPAINT, sent|optional },
1534     { WM_GETTEXT, sent|optional|defwinproc },
1535     { WM_GETTEXT, sent|optional|defwinproc },
1536     { WM_ERASEBKGND, sent|optional },
1537     { WM_CTLCOLORDLG, sent|optional|defwinproc },
1538     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1539     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1540     { WM_MOVE, sent },
1541     { 0 }
1542 };
1543 /* Calling EndDialog for a custom dialog (32) */
1544 static const struct message WmEndCustomDialogSeq[] = {
1545     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1546     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1547     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1548     { WM_GETTEXT, sent|optional },
1549     { HCBT_ACTIVATE, hook },
1550     { WM_NCACTIVATE, sent|wparam, 0 },
1551     { WM_GETTEXT, sent|optional|defwinproc },
1552     { WM_GETTEXT, sent|optional|defwinproc },
1553     { WM_ACTIVATE, sent|wparam, 0 },
1554     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1555     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1556     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1557     { WM_GETTEXT, sent|optional|defwinproc },
1558     { WM_GETTEXT, sent|optional|defwinproc },
1559     { HCBT_SETFOCUS, hook },
1560     { WM_KILLFOCUS, sent },
1561     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1562     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1563     { WM_IME_NOTIFY, sent|wparam|optional, 1 },
1564     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1565     { WM_SETFOCUS, sent|parent|defwinproc },
1566     { 0 }
1567 };
1568 /* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
1569 static const struct message WmShowCustomDialogSeq[] = {
1570     { WM_SHOWWINDOW, sent|wparam, 1 },
1571     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1572     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1573     { HCBT_ACTIVATE, hook },
1574     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1575 
1576     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1577 
1578     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1579     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
1580     { WM_NCACTIVATE, sent },
1581     { WM_ACTIVATE, sent|wparam, 1 },
1582     { WM_GETTEXT, sent|optional },
1583 
1584     { WM_KILLFOCUS, sent|parent },
1585     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1586     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1587     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1588     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1589     { WM_SETFOCUS, sent },
1590     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1591     { WM_NCPAINT, sent|wparam, 1 },
1592     { WM_ERASEBKGND, sent },
1593     { WM_CTLCOLORDLG, sent|defwinproc },
1594     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1595     { 0 }
1596 };
1597 /* Creation and destruction of a modal dialog (32) */
1598 static const struct message WmModalDialogSeq[] = {
1599     { WM_CANCELMODE, sent|parent },
1600     { HCBT_SETFOCUS, hook },
1601     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1602     { WM_KILLFOCUS, sent|parent },
1603     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1604     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1605     { WM_ENABLE, sent|parent|wparam, 0 },
1606     { HCBT_CREATEWND, hook },
1607     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1608     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1609     { WM_SETFONT, sent },
1610     { WM_INITDIALOG, sent },
1611     { WM_CHANGEUISTATE, sent|optional },
1612     { WM_UPDATEUISTATE, sent|optional },
1613     { WM_SHOWWINDOW, sent },
1614     { HCBT_ACTIVATE, hook },
1615     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1616     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1617     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1618     { WM_NCACTIVATE, sent },
1619     { WM_GETTEXT, sent|optional },
1620     { WM_ACTIVATE, sent|wparam, 1 },
1621     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1622     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1623     { WM_NCPAINT, sent|optional },
1624     { WM_GETTEXT, sent|optional },
1625     { WM_ERASEBKGND, sent|optional },
1626     { WM_CTLCOLORDLG, sent|optional },
1627     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1628     { WM_GETTEXT, sent|optional },
1629     { WM_NCCALCSIZE, sent|optional },
1630     { WM_NCPAINT, sent|optional },
1631     { WM_GETTEXT, sent|optional },
1632     { WM_ERASEBKGND, sent|optional },
1633     { WM_CTLCOLORDLG, sent|optional },
1634     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1635     { WM_PAINT, sent|optional },
1636     { WM_CTLCOLORBTN, sent|optional },
1637     { WM_GETTITLEBARINFOEX, sent|optional },
1638     { WM_ENTERIDLE, sent|parent|optional },
1639     { WM_ENTERIDLE, sent|parent|optional },
1640     { WM_ENTERIDLE, sent|parent|optional },
1641     { WM_ENTERIDLE, sent|parent|optional },
1642     { WM_ENTERIDLE, sent|parent|optional },
1643     { WM_ENTERIDLE, sent|parent|optional },
1644     { WM_ENTERIDLE, sent|parent|optional },
1645     { WM_ENTERIDLE, sent|parent|optional },
1646     { WM_ENTERIDLE, sent|parent|optional },
1647     { WM_ENTERIDLE, sent|parent|optional },
1648     { WM_ENTERIDLE, sent|parent|optional },
1649     { WM_ENTERIDLE, sent|parent|optional },
1650     { WM_ENTERIDLE, sent|parent|optional },
1651     { WM_ENTERIDLE, sent|parent|optional },
1652     { WM_ENTERIDLE, sent|parent|optional },
1653     { WM_ENTERIDLE, sent|parent|optional },
1654     { WM_ENTERIDLE, sent|parent|optional },
1655     { WM_ENTERIDLE, sent|parent|optional },
1656     { WM_ENTERIDLE, sent|parent|optional },
1657     { WM_ENTERIDLE, sent|parent|optional },
1658     { WM_TIMER, sent },
1659     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1660     { WM_ENABLE, sent|parent|wparam, 1 },
1661     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1662     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1663     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1664     { WM_GETTEXT, sent|optional },
1665     { HCBT_ACTIVATE, hook },
1666     { WM_NCACTIVATE, sent|wparam, 0 },
1667     { WM_GETTEXT, sent|optional },
1668     { WM_ACTIVATE, sent|wparam, 0 },
1669     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1670     { WM_WINDOWPOSCHANGING, sent|optional },
1671     { WM_WINDOWPOSCHANGED, sent|optional },
1672     { HCBT_SETFOCUS, hook },
1673     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1674     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1675     { WM_SETFOCUS, sent|parent|defwinproc },
1676     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 },
1677     { HCBT_DESTROYWND, hook },
1678     { 0x0090, sent|optional },
1679     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1680     { WM_DESTROY, sent },
1681     { WM_NCDESTROY, sent },
1682     { 0 }
1683 };
1684 static const struct message WmModalDialogSeq_2[] = {
1685     { WM_CANCELMODE, sent },
1686     { HCBT_SETFOCUS, hook },
1687     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1688     { WM_KILLFOCUS, sent },
1689     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1690     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1691     { WM_ENABLE, sent|wparam, 0 },
1692     { HCBT_CREATEWND, hook },
1693     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1694     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1695     { WM_SETFONT, sent },
1696     { WM_INITDIALOG, sent },
1697     { WM_CHANGEUISTATE, sent|optional },
1698     { WM_UPDATEUISTATE, sent|optional },
1699     { WM_ENABLE, sent|wparam, 1 },
1700     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1701     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1702     { WM_CHANGEUISTATE, sent|optional },
1703     { WM_UPDATEUISTATE, sent|optional },
1704     { HCBT_DESTROYWND, hook },
1705     { 0x0090, sent|optional },
1706     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1707     { WM_DESTROY, sent },
1708     { WM_NCDESTROY, sent },
1709     { 0 }
1710 };
1711 /* SetMenu for NonVisible windows with size change*/
1712 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
1713     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1714     { WM_NCCALCSIZE, sent|wparam, 1 },
1715     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1716     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
1717     { WM_MOVE, sent|defwinproc },
1718     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1719     { WM_NCCALCSIZE,sent|wparam|optional, 1 }, /* XP */
1720     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1721     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1722     { WM_GETTEXT, sent|optional },
1723     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1724     { 0 }
1725 };
1726 /* SetMenu for NonVisible windows with no size change */
1727 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
1728     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1729     { WM_NCCALCSIZE, sent|wparam, 1 },
1730     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1731     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1732     { 0 }
1733 };
1734 /* SetMenu for Visible windows with size change */
1735 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
1736     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1737     { WM_NCCALCSIZE, sent|wparam, 1 },
1738     { 0x0093, sent|defwinproc|optional },
1739     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1740     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1741     { 0x0093, sent|defwinproc|optional },
1742     { 0x0093, sent|defwinproc|optional },
1743     { 0x0091, sent|defwinproc|optional },
1744     { 0x0092, sent|defwinproc|optional },
1745     { WM_GETTEXT, sent|defwinproc|optional },
1746     { WM_ERASEBKGND, sent|optional },
1747     { WM_ACTIVATE, sent|optional },
1748     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1749     { WM_MOVE, sent|defwinproc },
1750     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1751     { 0x0093, sent|optional },
1752     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1753     { 0x0093, sent|defwinproc|optional },
1754     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1755     { 0x0093, sent|defwinproc|optional },
1756     { 0x0093, sent|defwinproc|optional },
1757     { 0x0091, sent|defwinproc|optional },
1758     { 0x0092, sent|defwinproc|optional },
1759     { WM_ERASEBKGND, sent|optional },
1760     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1761     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1762     { 0 }
1763 };
1764 /* SetMenu for Visible windows with no size change */
1765 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
1766     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1767     { WM_NCCALCSIZE, sent|wparam, 1 },
1768     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1769     { WM_GETTEXT, sent|defwinproc|optional },
1770     { WM_ERASEBKGND, sent|optional },
1771     { WM_ACTIVATE, sent|optional },
1772     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1773     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1774     { 0 }
1775 };
1776 /* DrawMenuBar for a visible window */
1777 static const struct message WmDrawMenuBarSeq[] =
1778 {
1779     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1780     { WM_NCCALCSIZE, sent|wparam, 1 },
1781     { 0x0093, sent|defwinproc|optional },
1782     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1783     { 0x0093, sent|defwinproc|optional },
1784     { 0x0093, sent|defwinproc|optional },
1785     { 0x0091, sent|defwinproc|optional },
1786     { 0x0092, sent|defwinproc|optional },
1787     { WM_GETTEXT, sent|defwinproc|optional },
1788     { WM_ERASEBKGND, sent|optional },
1789     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1790     { 0x0093, sent|optional },
1791     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1792     { 0 }
1793 };
1794 
1795 static const struct message WmSetRedrawFalseSeq[] =
1796 {
1797     { WM_SETREDRAW, sent|wparam, 0 },
1798     { 0 }
1799 };
1800 
1801 static const struct message WmSetRedrawTrueSeq[] =
1802 {
1803     { WM_SETREDRAW, sent|wparam, 1 },
1804     { 0 }
1805 };
1806 
1807 static const struct message WmEnableWindowSeq_1[] =
1808 {
1809     { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1810     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1811     { HCBT_SETFOCUS, hook|optional },
1812     { WM_KILLFOCUS, sent|optional },
1813     { WM_ENABLE, sent|wparam|lparam, FALSE, 0 },
1814     { 0 }
1815 };
1816 
1817 static const struct message WmEnableWindowSeq_2[] =
1818 {
1819     { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1820     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1821     { 0 }
1822 };
1823 
1824 static const struct message WmEnableWindowSeq_3[] =
1825 {
1826     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1827     { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
1828     { 0 }
1829 };
1830 
1831 static const struct message WmEnableWindowSeq_4[] =
1832 {
1833     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1834     { 0 }
1835 };
1836 
1837 static const struct message WmGetScrollRangeSeq[] =
1838 {
1839     { SBM_GETRANGE, sent },
1840     { 0 }
1841 };
1842 static const struct message WmGetScrollInfoSeq[] =
1843 {
1844     { SBM_GETSCROLLINFO, sent },
1845     { 0 }
1846 };
1847 static const struct message WmSetScrollRangeSeq[] =
1848 {
1849     /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
1850        sends SBM_SETSCROLLINFO.
1851      */
1852     { SBM_SETSCROLLINFO, sent },
1853     { 0 }
1854 };
1855 /* SetScrollRange for a window without a non-client area */
1856 static const struct message WmSetScrollRangeHSeq_empty[] =
1857 {
1858     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_HSCROLL, 0 },
1859     { 0 }
1860 };
1861 static const struct message WmSetScrollRangeVSeq_empty[] =
1862 {
1863     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_VSCROLL, 0 },
1864     { 0 }
1865 };
1866 static const struct message WmSetScrollRangeHVSeq[] =
1867 {
1868     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1869     { WM_NCCALCSIZE, sent|wparam, 1 },
1870     { WM_GETTEXT, sent|defwinproc|optional },
1871     { WM_ERASEBKGND, sent|optional },
1872     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1873     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1874     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1875     { 0 }
1876 };
1877 /* SetScrollRange for a window with a non-client area */
1878 static const struct message WmSetScrollRangeHV_NC_Seq[] =
1879 {
1880     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1881     { WM_NCCALCSIZE, sent|wparam, 1 },
1882     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1883     { WM_NCPAINT, sent|optional },
1884     { WM_STYLECHANGING, sent|defwinproc|optional },
1885     { WM_STYLECHANGED, sent|defwinproc|optional },
1886     { WM_STYLECHANGING, sent|defwinproc|optional },
1887     { WM_STYLECHANGED, sent|defwinproc|optional },
1888     { WM_STYLECHANGING, sent|defwinproc|optional },
1889     { WM_STYLECHANGED, sent|defwinproc|optional },
1890     { WM_STYLECHANGING, sent|defwinproc|optional },
1891     { WM_STYLECHANGED, sent|defwinproc|optional },
1892     { WM_GETTEXT, sent|defwinproc|optional },
1893     { WM_GETTEXT, sent|defwinproc|optional },
1894     { WM_ERASEBKGND, sent|optional },
1895     { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
1896     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOCLIENTSIZE },
1897     { WM_SIZE, sent|defwinproc|optional },
1898     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1899     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1900     { WM_GETTEXT, sent|optional },
1901     { WM_GETTEXT, sent|optional },
1902     { WM_GETTEXT, sent|optional },
1903     { WM_GETTEXT, sent|optional },
1904     { 0 }
1905 };
1906 /* test if we receive the right sequence of messages */
1907 /* after calling ShowWindow( SW_SHOWNA) */
1908 static const struct message WmSHOWNAChildInvisParInvis[] = {
1909     { WM_SHOWWINDOW, sent|wparam, 1 },
1910     { 0 }
1911 };
1912 static const struct message WmSHOWNAChildVisParInvis[] = {
1913     { WM_SHOWWINDOW, sent|wparam, 1 },
1914     { 0 }
1915 };
1916 static const struct message WmSHOWNAChildVisParVis[] = {
1917     { WM_SHOWWINDOW, sent|wparam, 1 },
1918     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1919     { 0 }
1920 };
1921 static const struct message WmSHOWNAChildInvisParVis[] = {
1922     { WM_SHOWWINDOW, sent|wparam, 1 },
1923     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1924     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1925     { WM_ERASEBKGND, sent|optional },
1926     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOCLIENTMOVE },
1927     { 0 }
1928 };
1929 static const struct message WmSHOWNATopVisible[] = {
1930     { WM_SHOWWINDOW, sent|wparam, 1 },
1931     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1932     { WM_NCPAINT, sent|wparam|optional, 1 },
1933     { WM_GETTEXT, sent|defwinproc|optional },
1934     { WM_ERASEBKGND, sent|optional },
1935     { WM_WINDOWPOSCHANGED, sent|optional },
1936     { 0 }
1937 };
1938 static const struct message WmSHOWNATopInvisible[] = {
1939     { WM_NOTIFYFORMAT, sent|optional },
1940     { WM_QUERYUISTATE, sent|optional },
1941     { WM_WINDOWPOSCHANGING, sent|optional },
1942     { WM_GETMINMAXINFO, sent|optional },
1943     { WM_NCCALCSIZE, sent|optional },
1944     { WM_WINDOWPOSCHANGED, sent|optional },
1945     { WM_SHOWWINDOW, sent|wparam, 1 },
1946     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1947     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1948     { WM_NCPAINT, sent|wparam|optional, 1 },
1949     { WM_GETTEXT, sent|defwinproc|optional },
1950     { WM_ERASEBKGND, sent|optional },
1951     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1952     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1953     { WM_NCPAINT, sent|wparam|optional, 1 },
1954     { WM_ERASEBKGND, sent|optional },
1955     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1956     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1957     { WM_MOVE, sent },
1958     { 0 }
1959 };
1960 
1961 static const struct message WmTrackPopupMenu[] = {
1962     { HCBT_CREATEWND, hook },
1963     { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1964     { WM_INITMENU, sent|lparam, 0, 0 },
1965     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1966     { 0x0093, sent|optional },
1967     { 0x0094, sent|optional },
1968     { 0x0094, sent|optional },
1969     { WM_ENTERIDLE, sent|wparam, 2 },
1970     { WM_CAPTURECHANGED, sent },
1971     { HCBT_DESTROYWND, hook },
1972     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1973     { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
1974     { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1975     { 0 }
1976 };
1977 
1978 static const struct message WmTrackPopupMenuEsc[] = {
1979     { 0 }
1980 };
1981 
1982 static const struct message WmTrackPopupMenuCapture[] = {
1983     { HCBT_CREATEWND, hook },
1984     { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1985     { WM_CAPTURECHANGED, sent },
1986     { WM_INITMENU, sent|lparam, 0, 0 },
1987     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1988     { 0x0093, sent|optional },
1989     { 0x0094, sent|optional },
1990     { 0x0094, sent|optional },
1991     { WM_ENTERIDLE, sent|wparam, 2 },
1992     { WM_CAPTURECHANGED, sent },
1993     { HCBT_DESTROYWND, hook },
1994     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1995     { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
1996     { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1997     { 0 }
1998 };
1999 
2000 static const struct message WmTrackPopupMenuEmpty[] = {
2001     { HCBT_CREATEWND, hook },
2002     { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
2003     { WM_INITMENU, sent|lparam, 0, 0 },
2004     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
2005     { 0x0093, sent|optional },
2006     { 0x0094, sent|optional },
2007     { 0x0094, sent|optional },
2008     { WM_CAPTURECHANGED, sent },
2009     { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
2010     { HCBT_DESTROYWND, hook },
2011     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
2012     { 0 }
2013 };
2014 
2015 static const struct message WmTrackPopupMenuAbort[] = {
2016     { HCBT_CREATEWND, hook },
2017     { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
2018     { WM_INITMENU, sent|lparam, 0, 0 },
2019     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
2020     { 0x0093, sent|optional },
2021     { 0x0094, sent|optional },
2022     { 0x0094, sent|optional },
2023     { WM_CAPTURECHANGED, sent },
2024     { HCBT_DESTROYWND, hook },
2025     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
2026     { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
2027     { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
2028     { 0 }
2029 };
2030 
2031 static BOOL after_end_dialog, test_def_id, paint_loop_done;
2032 static int sequence_cnt, sequence_size;
2033 static struct recvd_message* sequence;
2034 static int log_all_parent_messages;
2035 static CRITICAL_SECTION sequence_cs;
2036 
2037 /* user32 functions */
2038 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
2039 static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO);
2040 static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG);
2041 static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO);
2042 static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD);
2043 static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*);
2044 static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
2045 static BOOL (WINAPI *pGetMonitorInfoA)(HMONITOR,LPMONITORINFO);
2046 static HMONITOR (WINAPI *pMonitorFromPoint)(POINT,DWORD);
2047 static BOOL (WINAPI *pUpdateLayeredWindow)(HWND,HDC,POINT*,SIZE*,HDC,POINT*,COLORREF,BLENDFUNCTION*,DWORD);
2048 static UINT_PTR (WINAPI *pSetSystemTimer)(HWND, UINT_PTR, UINT, TIMERPROC);
2049 static UINT_PTR (WINAPI *pKillSystemTimer)(HWND, UINT_PTR);
2050 static UINT_PTR (WINAPI *pSetCoalescableTimer)(HWND, UINT_PTR, UINT, TIMERPROC, ULONG);
2051 /* kernel32 functions */
2052 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
2053 
2054 static void init_procs(void)
2055 {
2056     HMODULE user32 = GetModuleHandleA("user32.dll");
2057     HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
2058 
2059 #define GET_PROC(dll, func) \
2060     p ## func = (void*)GetProcAddress(dll, #func); \
2061     if(!p ## func) { \
2062       trace("GetProcAddress(%s) failed\n", #func); \
2063     }
2064 
2065     GET_PROC(user32, GetAncestor)
2066     GET_PROC(user32, GetMenuInfo)
2067     GET_PROC(user32, NotifyWinEvent)
2068     GET_PROC(user32, SetMenuInfo)
2069     GET_PROC(user32, SetWinEventHook)
2070     GET_PROC(user32, TrackMouseEvent)
2071     GET_PROC(user32, UnhookWinEvent)
2072     GET_PROC(user32, GetMonitorInfoA)
2073     GET_PROC(user32, MonitorFromPoint)
2074     GET_PROC(user32, UpdateLayeredWindow)
2075     GET_PROC(user32, SetSystemTimer)
2076     GET_PROC(user32, KillSystemTimer)
2077     GET_PROC(user32, SetCoalescableTimer)
2078 
2079     GET_PROC(kernel32, GetCPInfoExA)
2080 
2081 #undef GET_PROC
2082 }
2083 
2084 static const char *get_winpos_flags(UINT flags)
2085 {
2086     static char buffer[300];
2087 
2088     buffer[0] = 0;
2089 #define DUMP(flag) do { if (flags & flag) { strcat( buffer, "|" #flag ); flags &= ~flag; } } while(0)
2090     DUMP( SWP_SHOWWINDOW );
2091     DUMP( SWP_HIDEWINDOW );
2092     DUMP( SWP_NOACTIVATE );
2093     DUMP( SWP_FRAMECHANGED );
2094     DUMP( SWP_NOCOPYBITS );
2095     DUMP( SWP_NOOWNERZORDER );
2096     DUMP( SWP_NOSENDCHANGING );
2097     DUMP( SWP_DEFERERASE );
2098     DUMP( SWP_ASYNCWINDOWPOS );
2099     DUMP( SWP_NOZORDER );
2100     DUMP( SWP_NOREDRAW );
2101     DUMP( SWP_NOSIZE );
2102     DUMP( SWP_NOMOVE );
2103     DUMP( SWP_NOCLIENTSIZE );
2104     DUMP( SWP_NOCLIENTMOVE );
2105     if (flags) sprintf(buffer + strlen(buffer),"|0x%04x", flags);
2106     return buffer + 1;
2107 #undef DUMP
2108 }
2109 
2110 static BOOL ignore_message( UINT message )
2111 {
2112     /* these are always ignored */
2113     return (message >= 0xc000 ||
2114             message == WM_GETICON ||
2115             message == WM_GETOBJECT ||
2116             message == WM_TIMECHANGE ||
2117             message == WM_DISPLAYCHANGE ||
2118             message == WM_DEVICECHANGE ||
2119             message == WM_DWMNCRENDERINGCHANGED);
2120 }
2121 
2122 static unsigned hash_Ly_W(const WCHAR *str)
2123 {
2124     unsigned hash = 0;
2125 
2126     for (; *str; str++)
2127         hash = hash * 1664525u + (unsigned char)(*str) + 1013904223u;
2128 
2129     return hash;
2130 }
2131 
2132 static unsigned hash_Ly(const char *str)
2133 {
2134     unsigned hash = 0;
2135 
2136     for (; *str; str++)
2137         hash = hash * 1664525u + (unsigned char)(*str) + 1013904223u;
2138 
2139     return hash;
2140 }
2141 
2142 #define add_message(msg) add_message_(__LINE__,msg);
2143 static void add_message_(int line, const struct recvd_message *msg)
2144 {
2145     struct recvd_message *seq;
2146 
2147     EnterCriticalSection( &sequence_cs );
2148     if (!sequence)
2149     {
2150 	sequence_size = 10;
2151 	sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof(*sequence) );
2152     }
2153     if (sequence_cnt == sequence_size)
2154     {
2155 	sequence_size *= 2;
2156 	sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof(*sequence) );
2157     }
2158     assert(sequence);
2159 
2160     seq = &sequence[sequence_cnt++];
2161     seq->hwnd = msg->hwnd;
2162     seq->message = msg->message;
2163     seq->flags = msg->flags;
2164     seq->wParam = msg->wParam;
2165     seq->lParam = msg->lParam;
2166     seq->line   = line;
2167     seq->descr  = msg->descr;
2168     seq->output[0] = 0;
2169     LeaveCriticalSection( &sequence_cs );
2170 
2171     if (msg->descr)
2172     {
2173         if (msg->flags & hook)
2174         {
2175             static const char * const CBT_code_name[10] =
2176             {
2177                 "HCBT_MOVESIZE",
2178                 "HCBT_MINMAX",
2179                 "HCBT_QS",
2180                 "HCBT_CREATEWND",
2181                 "HCBT_DESTROYWND",
2182                 "HCBT_ACTIVATE",
2183                 "HCBT_CLICKSKIPPED",
2184                 "HCBT_KEYSKIPPED",
2185                 "HCBT_SYSCOMMAND",
2186                 "HCBT_SETFOCUS"
2187             };
2188             const char *code_name = (msg->message <= HCBT_SETFOCUS) ? CBT_code_name[msg->message] : "Unknown";
2189 
2190             sprintf( seq->output, "%s: hook %d (%s) wp %08lx lp %08lx",
2191                      msg->descr, msg->message, code_name, msg->wParam, msg->lParam );
2192         }
2193         else if (msg->flags & winevent_hook)
2194         {
2195             sprintf( seq->output, "%s: winevent %p %08x %08lx %08lx",
2196                      msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
2197         }
2198         else
2199         {
2200             switch (msg->message)
2201             {
2202             case WM_WINDOWPOSCHANGING:
2203             case WM_WINDOWPOSCHANGED:
2204             {
2205                 WINDOWPOS *winpos = (WINDOWPOS *)msg->lParam;
2206 
2207                 sprintf( seq->output, "%s: %p WM_WINDOWPOS%s wp %08lx lp %08lx after %p x %d y %d cx %d cy %d flags %s",
2208                           msg->descr, msg->hwnd,
2209                           (msg->message == WM_WINDOWPOSCHANGING) ? "CHANGING" : "CHANGED",
2210                           msg->wParam, msg->lParam, winpos->hwndInsertAfter,
2211                           winpos->x, winpos->y, winpos->cx, winpos->cy,
2212                           get_winpos_flags(winpos->flags) );
2213 
2214                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2215                  * in the high word for internal purposes
2216                  */
2217                 seq->wParam = winpos->flags & 0xffff;
2218                 /* We are not interested in the flags that don't match under XP and Win9x */
2219                 seq->wParam &= ~SWP_NOZORDER;
2220                 break;
2221             }
2222 
2223             case WM_DRAWITEM:
2224             {
2225                 DRAW_ITEM_STRUCT di;
2226                 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)msg->lParam;
2227 
2228                 sprintf( seq->output, "%s: %p WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x",
2229                          msg->descr, msg->hwnd, dis->CtlType, dis->CtlID,
2230                          dis->itemID, dis->itemAction, dis->itemState);
2231 
2232                 di.u.lp = 0;
2233                 di.u.item.type = dis->CtlType;
2234                 di.u.item.ctl_id = dis->CtlID;
2235                 if (dis->CtlType == ODT_LISTBOX ||
2236                     dis->CtlType == ODT_COMBOBOX ||
2237                     dis->CtlType == ODT_MENU)
2238                     di.u.item.item_id = dis->itemID;
2239                 di.u.item.action = dis->itemAction;
2240                 di.u.item.state = dis->itemState;
2241 
2242                 seq->lParam = di.u.lp;
2243                 break;
2244             }
2245 
2246             case WM_MEASUREITEM:
2247             {
2248                 MEASURE_ITEM_STRUCT mi;
2249                 MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *)msg->lParam;
2250                 BOOL is_unicode_data = TRUE;
2251 
2252                 sprintf( seq->output, "%s: %p WM_MEASUREITEM: CtlType %#x, CtlID %#x, itemID %#x, itemData %#lx",
2253                          msg->descr, msg->hwnd, mis->CtlType, mis->CtlID,
2254                          mis->itemID, mis->itemData);
2255 
2256                 if (mis->CtlType == ODT_LISTBOX)
2257                 {
2258                     HWND ctrl = GetDlgItem(msg->hwnd, mis->CtlID);
2259                     is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS;
2260                 }
2261 
2262                 mi.u.wp = 0;
2263                 mi.u.item.CtlType = mis->CtlType;
2264                 mi.u.item.CtlID = mis->CtlID;
2265                 mi.u.item.itemID = mis->itemID;
2266                 mi.u.item.wParam = msg->wParam;
2267                 seq->wParam = mi.u.wp;
2268                 if (is_unicode_data)
2269                     seq->lParam = mis->itemData ? hash_Ly_W((const WCHAR *)mis->itemData) : 0;
2270                 else
2271                     seq->lParam = mis->itemData ? hash_Ly((const char *)mis->itemData) : 0;
2272                 break;
2273             }
2274 
2275             case WM_COMPAREITEM:
2276             {
2277                 COMPAREITEMSTRUCT *cis = (COMPAREITEMSTRUCT *)msg->lParam;
2278                 HWND ctrl = GetDlgItem(msg->hwnd, cis->CtlID);
2279                 BOOL is_unicode_data = TRUE;
2280 
2281                 ok(msg->wParam == cis->CtlID, "expected %#x, got %#lx\n", cis->CtlID, msg->wParam);
2282                 ok(cis->hwndItem == ctrl, "expected %p, got %p\n", ctrl, cis->hwndItem);
2283                 ok((int)cis->itemID1 >= 0, "expected >= 0, got %d\n", cis->itemID1);
2284                 ok((int)cis->itemID2 == -1, "expected -1, got %d\n", cis->itemID2);
2285 
2286                 sprintf( seq->output, "%s: %p WM_COMPAREITEM: CtlType %#x, CtlID %#x, itemID1 %#x, itemData1 %#lx, itemID2 %#x, itemData2 %#lx",
2287                          msg->descr, msg->hwnd, cis->CtlType, cis->CtlID,
2288                          cis->itemID1, cis->itemData1, cis->itemID2, cis->itemData2);
2289 
2290                 if (cis->CtlType == ODT_LISTBOX)
2291                     is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS;
2292 
2293                 if (is_unicode_data)
2294                 {
2295                     seq->wParam = cis->itemData1 ? hash_Ly_W((const WCHAR *)cis->itemData1) : 0;
2296                     seq->lParam = cis->itemData2 ? hash_Ly_W((const WCHAR *)cis->itemData2) : 0;
2297                 }
2298                 else
2299                 {
2300                     seq->wParam = cis->itemData1 ? hash_Ly((const char *)cis->itemData1) : 0;
2301                     seq->lParam = cis->itemData2 ? hash_Ly((const char *)cis->itemData2) : 0;
2302                 }
2303                 break;
2304             }
2305 
2306             default:
2307                 if (msg->message >= 0xc000) return;  /* ignore registered messages */
2308                 sprintf( seq->output, "%s: %p %04x wp %08lx lp %08lx",
2309                          msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
2310             }
2311             if (msg->flags & (sent|posted|parent|defwinproc|beginpaint))
2312                 sprintf( seq->output + strlen(seq->output), " (flags %x)", msg->flags );
2313         }
2314     }
2315 }
2316 
2317 /* try to make sure pending X events have been processed before continuing */
2318 static void flush_events(void)
2319 {
2320     MSG msg;
2321     int diff = 200;
2322     int min_timeout = 100;
2323     DWORD time = GetTickCount() + diff;
2324 
2325     while (diff > 0)
2326     {
2327         if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
2328         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
2329         diff = time - GetTickCount();
2330     }
2331 }
2332 
2333 static void flush_sequence(void)
2334 {
2335     EnterCriticalSection( &sequence_cs );
2336     HeapFree(GetProcessHeap(), 0, sequence);
2337     sequence = 0;
2338     sequence_cnt = sequence_size = 0;
2339     LeaveCriticalSection( &sequence_cs );
2340 }
2341 
2342 static void dump_sequence(const struct message *expected, const char *context, const char *file, int line)
2343 {
2344     const struct recvd_message *actual = sequence;
2345     unsigned int count = 0;
2346 
2347     trace_(file, line)("Failed sequence %s:\n", context );
2348     while (expected->message && actual->message)
2349     {
2350         if (actual->output[0])
2351         {
2352             if (expected->flags & hook)
2353             {
2354                 trace_(file, line)( "  %u: expected: hook %04x - actual: %s\n",
2355                                     count, expected->message, actual->output );
2356             }
2357             else if (expected->flags & winevent_hook)
2358             {
2359                 trace_(file, line)( "  %u: expected: winevent %04x - actual: %s\n",
2360                                     count, expected->message, actual->output );
2361             }
2362             else if (expected->flags & kbd_hook)
2363             {
2364                 trace_(file, line)( "  %u: expected: kbd %04x - actual: %s\n",
2365                                     count, expected->message, actual->output );
2366             }
2367             else
2368             {
2369                 trace_(file, line)( "  %u: expected: msg %04x - actual: %s\n",
2370                                     count, expected->message, actual->output );
2371             }
2372         }
2373 
2374 	if (expected->message == actual->message)
2375 	{
2376 	    if ((expected->flags & defwinproc) != (actual->flags & defwinproc) &&
2377                 (expected->flags & optional))
2378             {
2379                 /* don't match messages if their defwinproc status differs */
2380                 expected++;
2381             }
2382             else
2383             {
2384                 expected++;
2385                 actual++;
2386             }
2387 	}
2388 	/* silently drop winevent messages if there is no support for them */
2389 	else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
2390 	    expected++;
2391         else
2392         {
2393             expected++;
2394             actual++;
2395         }
2396         count++;
2397     }
2398 
2399     /* optional trailing messages */
2400     while (expected->message && ((expected->flags & optional) ||
2401 	    ((expected->flags & winevent_hook) && !hEvent_hook)))
2402     {
2403         trace_(file, line)( "  %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2404 	expected++;
2405         count++;
2406     }
2407 
2408     if (expected->message)
2409     {
2410         trace_(file, line)( "  %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2411         return;
2412     }
2413 
2414     while (actual->message && actual->output[0])
2415     {
2416         trace_(file, line)( "  %u: expected: nothing - actual: %s\n", count, actual->output );
2417         actual++;
2418         count++;
2419     }
2420 }
2421 
2422 #define ok_sequence( exp, contx, todo) \
2423         ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
2424 
2425 
2426 static void ok_sequence_(const struct message *expected_list, const char *context, BOOL todo,
2427                          const char *file, int line)
2428 {
2429     static const struct recvd_message end_of_sequence;
2430     const struct message *expected = expected_list;
2431     const struct recvd_message *actual;
2432     int failcount = 0, dump = 0;
2433     unsigned int count = 0;
2434 
2435     add_message(&end_of_sequence);
2436 
2437     actual = sequence;
2438 
2439     while (expected->message && actual->message)
2440     {
2441 	if (expected->message == actual->message &&
2442             !((expected->flags ^ actual->flags) & (hook|winevent_hook|kbd_hook)))
2443 	{
2444 	    if (expected->flags & wparam)
2445 	    {
2446 		if (((expected->wParam ^ actual->wParam) & ~expected->wp_mask) && todo)
2447 		{
2448 		    todo_wine {
2449                         failcount ++;
2450                         if (strcmp(winetest_platform, "wine")) dump++;
2451                         ok_( file, line) (FALSE,
2452 			    "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2453                             context, count, expected->message, expected->wParam, actual->wParam);
2454 		    }
2455 		}
2456 		else
2457                 {
2458                     ok_( file, line)( ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) == 0,
2459                                      "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2460                                      context, count, expected->message, expected->wParam, actual->wParam);
2461                     if ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) dump++;
2462                 }
2463 
2464 	    }
2465 	    if (expected->flags & lparam)
2466             {
2467 		if (((expected->lParam ^ actual->lParam) & ~expected->lp_mask) && todo)
2468 		{
2469 		    todo_wine {
2470                         failcount ++;
2471                         if (strcmp(winetest_platform, "wine")) dump++;
2472                         ok_( file, line) (FALSE,
2473 			    "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2474                             context, count, expected->message, expected->lParam, actual->lParam);
2475 		    }
2476 		}
2477 		else
2478                 {
2479                     ok_( file, line)(((expected->lParam ^ actual->lParam) & ~expected->lp_mask) == 0,
2480                                      "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2481                                      context, count, expected->message, expected->lParam, actual->lParam);
2482                     if ((expected->lParam ^ actual->lParam) & ~expected->lp_mask) dump++;
2483                 }
2484             }
2485 	    if ((expected->flags & optional) &&
2486                 ((expected->flags ^ actual->flags) & (defwinproc|parent)))
2487             {
2488                 /* don't match optional messages if their defwinproc or parent status differs */
2489                 expected++;
2490                 count++;
2491                 continue;
2492             }
2493 	    if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
2494 	    {
2495 		    todo_wine {
2496                         failcount ++;
2497                         if (strcmp(winetest_platform, "wine")) dump++;
2498                         ok_( file, line) (FALSE,
2499                             "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2500                             context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2501 		    }
2502 	    }
2503 	    else
2504             {
2505 	        ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
2506 		    "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2507                     context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2508                 if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) dump++;
2509             }
2510 
2511 	    ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
2512 		"%s: %u: the msg 0x%04x should %shave been sent by BeginPaint\n",
2513                 context, count, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
2514             if ((expected->flags & beginpaint) != (actual->flags & beginpaint)) dump++;
2515 
2516 	    ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
2517 		"%s: %u: the msg 0x%04x should have been %s\n",
2518                 context, count, expected->message, (expected->flags & posted) ? "posted" : "sent");
2519             if ((expected->flags & (sent|posted)) != (actual->flags & (sent|posted))) dump++;
2520 
2521 	    ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
2522 		"%s: %u: the msg 0x%04x was expected in %s\n",
2523                 context, count, expected->message, (expected->flags & parent) ? "parent" : "child");
2524             if ((expected->flags & parent) != (actual->flags & parent)) dump++;
2525 
2526 	    ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
2527 		"%s: %u: the msg 0x%04x should have been sent by a hook\n",
2528                 context, count, expected->message);
2529             if ((expected->flags & hook) != (actual->flags & hook)) dump++;
2530 
2531 	    ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
2532 		"%s: %u: the msg 0x%04x should have been sent by a winevent hook\n",
2533                 context, count, expected->message);
2534             if ((expected->flags & winevent_hook) != (actual->flags & winevent_hook)) dump++;
2535 
2536 	    ok_( file, line) ((expected->flags & kbd_hook) == (actual->flags & kbd_hook),
2537 		"%s: %u: the msg 0x%04x should have been sent by a keyboard hook\n",
2538                 context, count, expected->message);
2539             if ((expected->flags & kbd_hook) != (actual->flags & kbd_hook)) dump++;
2540 
2541 	    expected++;
2542 	    actual++;
2543 	}
2544 	/* silently drop hook messages if there is no support for them */
2545 	else if ((expected->flags & optional) ||
2546                  ((expected->flags & hook) && !hCBT_hook) ||
2547                  ((expected->flags & winevent_hook) && !hEvent_hook) ||
2548                  ((expected->flags & kbd_hook) && !hKBD_hook))
2549 	    expected++;
2550 	else if (todo)
2551 	{
2552             failcount++;
2553             todo_wine {
2554                 if (strcmp(winetest_platform, "wine")) dump++;
2555                 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2556                                   context, count, expected->message, actual->message);
2557             }
2558             goto done;
2559         }
2560         else
2561         {
2562             ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2563                               context, count, expected->message, actual->message);
2564             dump++;
2565             expected++;
2566             actual++;
2567         }
2568         count++;
2569     }
2570 
2571     /* skip all optional trailing messages */
2572     while (expected->message && ((expected->flags & optional) ||
2573                                  ((expected->flags & hook) && !hCBT_hook) ||
2574                                  ((expected->flags & winevent_hook) && !hEvent_hook)))
2575 	expected++;
2576 
2577     if (todo)
2578     {
2579         todo_wine {
2580             if (expected->message || actual->message) {
2581                 failcount++;
2582                 if (strcmp(winetest_platform, "wine")) dump++;
2583                 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2584                                   context, count, expected->message, actual->message);
2585             }
2586         }
2587     }
2588     else
2589     {
2590         if (expected->message || actual->message)
2591         {
2592             dump++;
2593             ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2594                               context, count, expected->message, actual->message);
2595         }
2596     }
2597     if( todo && !failcount) /* succeeded yet marked todo */
2598         todo_wine {
2599             if (!strcmp(winetest_platform, "wine")) dump++;
2600             ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
2601         }
2602 
2603 done:
2604     if (dump) dump_sequence(expected_list, context, file, line);
2605     flush_sequence();
2606 }
2607 
2608 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT))
2609 
2610 /******************************** MDI test **********************************/
2611 
2612 /* CreateWindow for MDI frame window, initially visible */
2613 static const struct message WmCreateMDIframeSeq[] = {
2614     { HCBT_CREATEWND, hook },
2615     { WM_GETMINMAXINFO, sent },
2616     { WM_NCCREATE, sent },
2617     { WM_NCCALCSIZE, sent|wparam, 0 },
2618     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2619     { WM_CREATE, sent },
2620     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2621     { WM_NOTIFYFORMAT, sent|optional },
2622     { WM_QUERYUISTATE, sent|optional },
2623     { WM_WINDOWPOSCHANGING, sent|optional },
2624     { WM_GETMINMAXINFO, sent|optional },
2625     { WM_NCCALCSIZE, sent|optional },
2626     { WM_WINDOWPOSCHANGED, sent|optional },
2627     { WM_SHOWWINDOW, sent|wparam, 1 },
2628     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2629     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2630     { HCBT_ACTIVATE, hook },
2631     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
2632     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
2633     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
2634     { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
2635     { WM_NCACTIVATE, sent },
2636     { WM_GETTEXT, sent|defwinproc|optional },
2637     { WM_ACTIVATE, sent|wparam, 1 },
2638     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
2639     { HCBT_SETFOCUS, hook },
2640     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2641     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2642     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2643     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
2644     /* Win9x adds SWP_NOZORDER below */
2645     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2646     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2647     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2648     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2649     { WM_MOVE, sent },
2650     { 0 }
2651 };
2652 /* DestroyWindow for MDI frame window, initially visible */
2653 static const struct message WmDestroyMDIframeSeq[] = {
2654     { HCBT_DESTROYWND, hook },
2655     { 0x0090, sent|optional },
2656     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2657     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2658     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2659     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2660     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
2661     { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2662     { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
2663     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
2664     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2665     { WM_DESTROY, sent },
2666     { WM_NCDESTROY, sent },
2667     { 0 }
2668 };
2669 /* CreateWindow for MDI client window, initially visible */
2670 static const struct message WmCreateMDIclientSeq[] = {
2671     { HCBT_CREATEWND, hook },
2672     { WM_NCCREATE, sent },
2673     { WM_NCCALCSIZE, sent|wparam, 0 },
2674     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2675     { WM_CREATE, sent },
2676     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2677     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2678     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2679     { WM_MOVE, sent },
2680     { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
2681     { WM_SHOWWINDOW, sent|wparam, 1 },
2682     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2683     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2684     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2685     { 0 }
2686 };
2687 /* ShowWindow(SW_SHOW) for MDI client window */
2688 static const struct message WmShowMDIclientSeq[] = {
2689     { WM_SHOWWINDOW, sent|wparam, 1 },
2690     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2691     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2692     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2693     { 0 }
2694 };
2695 /* ShowWindow(SW_HIDE) for MDI client window */
2696 static const struct message WmHideMDIclientSeq[] = {
2697     { WM_SHOWWINDOW, sent|wparam, 0 },
2698     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2699     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
2700     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
2701     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2702     { 0 }
2703 };
2704 /* DestroyWindow for MDI client window, initially visible */
2705 static const struct message WmDestroyMDIclientSeq[] = {
2706     { HCBT_DESTROYWND, hook },
2707     { 0x0090, sent|optional },
2708     { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
2709     { WM_SHOWWINDOW, sent|wparam, 0 },
2710     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2711     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2712     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2713     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2714     { WM_DESTROY, sent },
2715     { WM_NCDESTROY, sent },
2716     { 0 }
2717 };
2718 /* CreateWindow for MDI child window, initially visible */
2719 static const struct message WmCreateMDIchildVisibleSeq[] = {
2720     { HCBT_CREATEWND, hook },
2721     { WM_NCCREATE, sent },
2722     { WM_NCCALCSIZE, sent|wparam, 0 },
2723     { WM_CREATE, sent },
2724     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2725     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2726     { WM_MOVE, sent },
2727     /* Win2k sends wparam set to
2728      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2729      * while Win9x doesn't bother to set child window id according to
2730      * CLIENTCREATESTRUCT.idFirstChild
2731      */
2732     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2733     { WM_SHOWWINDOW, sent|wparam, 1 },
2734     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2735     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2736     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2737     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2738     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2739     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2740     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2741 
2742     /* Win9x: message sequence terminates here. */
2743 
2744     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2745     { HCBT_SETFOCUS, hook }, /* in MDI client */
2746     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2747     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2748     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2749     { WM_SETFOCUS, sent }, /* in MDI client */
2750     { HCBT_SETFOCUS, hook },
2751     { WM_KILLFOCUS, sent }, /* in MDI client */
2752     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2753     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2754     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2755     { WM_SETFOCUS, sent|defwinproc },
2756     { WM_MDIACTIVATE, sent|defwinproc },
2757     { 0 }
2758 };
2759 /* WM_CHILDACTIVATE sent to disabled window */
2760 static const struct message WmChildActivateDisabledWindowSeq[] = {
2761     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2762     { 0 }
2763 };
2764 /* WM_CHILDACTIVATE sent to enabled window */
2765 static const struct message WmChildActivateWindowSeq[] = {
2766     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2767     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 },
2768     { WM_MDIACTIVATE, sent|defwinproc },
2769     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2770     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2771     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2772     { HCBT_SETFOCUS, hook },
2773     { WM_KILLFOCUS, sent|defwinproc },
2774     { WM_SETFOCUS, sent },
2775     { HCBT_SETFOCUS, hook },
2776     { WM_KILLFOCUS, sent },
2777     { WM_SETFOCUS, sent|defwinproc },
2778     { WM_MDIACTIVATE, sent|defwinproc },
2779     { 0 }
2780 };
2781 /* CreateWindow for MDI child window with invisible parent */
2782 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
2783     { HCBT_CREATEWND, hook },
2784     { WM_GETMINMAXINFO, sent },
2785     { WM_NCCREATE, sent },
2786     { WM_NCCALCSIZE, sent|wparam, 0 },
2787     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2788     { WM_CREATE, sent },
2789     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2790     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2791     { WM_MOVE, sent },
2792     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2793     { WM_SHOWWINDOW, sent|wparam, 1 },
2794     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2795     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2796     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2797     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2798 
2799     /* Win9x: message sequence terminates here. */
2800 
2801     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2802     { HCBT_SETFOCUS, hook }, /* in MDI client */
2803     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2804     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2805     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2806     { WM_SETFOCUS, sent }, /* in MDI client */
2807     { HCBT_SETFOCUS, hook },
2808     { WM_KILLFOCUS, sent }, /* in MDI client */
2809     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2810     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2811     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2812     { WM_SETFOCUS, sent|defwinproc },
2813     { WM_MDIACTIVATE, sent|defwinproc },
2814     { 0 }
2815 };
2816 /* DestroyWindow for MDI child window, initially visible */
2817 static const struct message WmDestroyMDIchildVisibleSeq[] = {
2818     { HCBT_DESTROYWND, hook },
2819     /* Win2k sends wparam set to
2820      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2821      * while Win9x doesn't bother to set child window id according to
2822      * CLIENTCREATESTRUCT.idFirstChild
2823      */
2824     { 0x0090, sent|optional },
2825     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2826     { WM_SHOWWINDOW, sent|wparam, 0 },
2827     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2828     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2829     { WM_ERASEBKGND, sent|parent|optional },
2830     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2831 
2832     /* { WM_DESTROY, sent }
2833      * Win9x: message sequence terminates here.
2834      */
2835 
2836     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2837     { WM_KILLFOCUS, sent },
2838     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2839     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2840     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2841     { WM_SETFOCUS, sent }, /* in MDI client */
2842 
2843     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2844     { WM_KILLFOCUS, sent }, /* in MDI client */
2845     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2846     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2847     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2848     { WM_SETFOCUS, sent }, /* in MDI client */
2849 
2850     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2851 
2852     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2853     { WM_KILLFOCUS, sent },
2854     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2855     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2856     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2857     { WM_SETFOCUS, sent }, /* in MDI client */
2858 
2859     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2860     { WM_KILLFOCUS, sent }, /* in MDI client */
2861     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2862     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2863     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2864     { WM_SETFOCUS, sent }, /* in MDI client */
2865 
2866     { WM_DESTROY, sent },
2867 
2868     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2869     { WM_KILLFOCUS, sent },
2870     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2871     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2872     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2873     { WM_SETFOCUS, sent }, /* in MDI client */
2874 
2875     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2876     { WM_KILLFOCUS, sent }, /* in MDI client */
2877     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2878     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2879     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2880     { WM_SETFOCUS, sent }, /* in MDI client */
2881 
2882     { WM_NCDESTROY, sent },
2883     { 0 }
2884 };
2885 /* CreateWindow for MDI child window, initially invisible */
2886 static const struct message WmCreateMDIchildInvisibleSeq[] = {
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     /* Win2k sends wparam set to
2895      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2896      * while Win9x doesn't bother to set child window id according to
2897      * CLIENTCREATESTRUCT.idFirstChild
2898      */
2899     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2900     { 0 }
2901 };
2902 /* DestroyWindow for MDI child window, initially invisible */
2903 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
2904     { HCBT_DESTROYWND, hook },
2905     /* Win2k sends wparam set to
2906      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2907      * while Win9x doesn't bother to set child window id according to
2908      * CLIENTCREATESTRUCT.idFirstChild
2909      */
2910     { 0x0090, sent|optional },
2911     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2912     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2913     { WM_DESTROY, sent },
2914     { WM_NCDESTROY, sent },
2915     /* FIXME: Wine destroys an icon/title window while Windows doesn't */
2916     { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */
2917     { 0 }
2918 };
2919 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
2920 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
2921     { HCBT_CREATEWND, hook },
2922     { WM_NCCREATE, sent },
2923     { WM_NCCALCSIZE, sent|wparam, 0 },
2924     { WM_CREATE, sent },
2925     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2926     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2927     { WM_MOVE, sent },
2928     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2929     { WM_GETMINMAXINFO, sent },
2930     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED  },
2931     { WM_NCCALCSIZE, sent|wparam, 1 },
2932     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2933     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2934      /* in MDI frame */
2935     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2936     { WM_NCCALCSIZE, sent|wparam, 1 },
2937     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2938     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2939     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2940     /* Win2k sends wparam set to
2941      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2942      * while Win9x doesn't bother to set child window id according to
2943      * CLIENTCREATESTRUCT.idFirstChild
2944      */
2945     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2946     { WM_SHOWWINDOW, sent|wparam, 1 },
2947     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2948     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2949     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2950     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2951     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2952     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2953     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_FRAMECHANGED },
2954 
2955     /* Win9x: message sequence terminates here. */
2956 
2957     { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
2958     { HCBT_SETFOCUS, hook|optional }, /* in MDI client */
2959     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2960     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2961     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2962     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2963     { HCBT_SETFOCUS, hook|optional },
2964     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
2965     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2966     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2967     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2968     { WM_SETFOCUS, sent|defwinproc|optional },
2969     { WM_MDIACTIVATE, sent|defwinproc|optional },
2970      /* in MDI frame */
2971     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2972     { WM_NCCALCSIZE, sent|wparam, 1 },
2973     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2974     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2975     { 0 }
2976 };
2977 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
2978 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
2979     /* restore the 1st MDI child */
2980     { WM_SETREDRAW, sent|wparam, 0 },
2981     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2982     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2983     { WM_NCCALCSIZE, sent|wparam, 1 },
2984     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2985     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2986     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2987      /* in MDI frame */
2988     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2989     { WM_NCCALCSIZE, sent|wparam, 1 },
2990     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2991     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2992     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2993     { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
2994     /* create the 2nd MDI child */
2995     { HCBT_CREATEWND, hook },
2996     { WM_NCCREATE, sent },
2997     { WM_NCCALCSIZE, sent|wparam, 0 },
2998     { WM_CREATE, sent },
2999     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3000     { WM_SIZE, sent|wparam, SIZE_RESTORED },
3001     { WM_MOVE, sent },
3002     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3003     { WM_GETMINMAXINFO, sent },
3004     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3005     { WM_NCCALCSIZE, sent|wparam, 1 },
3006     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3007     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3008     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3009      /* in MDI frame */
3010     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3011     { WM_NCCALCSIZE, sent|wparam, 1 },
3012     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3013     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3014     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3015     /* Win2k sends wparam set to
3016      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3017      * while Win9x doesn't bother to set child window id according to
3018      * CLIENTCREATESTRUCT.idFirstChild
3019      */
3020     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3021     { WM_SHOWWINDOW, sent|wparam, 1 },
3022     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3023     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3024     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3025     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
3026     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
3027     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3028 
3029     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
3030     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
3031 
3032     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3033 
3034     /* Win9x: message sequence terminates here. */
3035 
3036     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3037     { HCBT_SETFOCUS, hook },
3038     { WM_KILLFOCUS, sent|defwinproc|optional }, /* in the 1st MDI child */
3039     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
3040     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3041     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3042     { WM_SETFOCUS, sent }, /* in MDI client */
3043     { HCBT_SETFOCUS, hook },
3044     { WM_KILLFOCUS, sent }, /* in MDI client */
3045     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3046     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3047     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3048     { WM_SETFOCUS, sent|defwinproc },
3049 
3050     { WM_MDIACTIVATE, sent|defwinproc },
3051      /* in MDI frame */
3052     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3053     { WM_NCCALCSIZE, sent|wparam, 1 },
3054     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3055     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3056     { 0 }
3057 };
3058 /* WM_MDICREATE MDI child window, initially visible and maximized */
3059 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
3060     { WM_MDICREATE, sent },
3061     { HCBT_CREATEWND, hook },
3062     { WM_NCCREATE, sent },
3063     { WM_NCCALCSIZE, sent|wparam, 0 },
3064     { WM_CREATE, sent },
3065     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3066     { WM_SIZE, sent|wparam, SIZE_RESTORED },
3067     { WM_MOVE, sent },
3068     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3069     { WM_GETMINMAXINFO, sent },
3070     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3071     { WM_NCCALCSIZE, sent|wparam, 1 },
3072     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3073     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3074 
3075      /* in MDI frame */
3076     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3077     { WM_NCCALCSIZE, sent|wparam, 1 },
3078     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3079     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3080     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3081 
3082     /* Win2k sends wparam set to
3083      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3084      * while Win9x doesn't bother to set child window id according to
3085      * CLIENTCREATESTRUCT.idFirstChild
3086      */
3087     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3088     { WM_SHOWWINDOW, sent|wparam, 1 },
3089     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3090 
3091     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3092 
3093     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3094     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
3095     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
3096 
3097     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3098     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3099 
3100     /* Win9x: message sequence terminates here. */
3101 
3102     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3103     { WM_SETFOCUS, sent|optional }, /* in MDI client */
3104     { HCBT_SETFOCUS, hook }, /* in MDI client */
3105     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3106     { WM_IME_NOTIFY, sent|wparam|optional, 2 },
3107     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
3108     { WM_SETFOCUS, sent|optional }, /* in MDI client */
3109     { HCBT_SETFOCUS, hook|optional },
3110     { WM_KILLFOCUS, sent }, /* in MDI client */
3111     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3112     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3113     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3114     { WM_SETFOCUS, sent|defwinproc },
3115 
3116     { WM_MDIACTIVATE, sent|defwinproc },
3117 
3118      /* in MDI child */
3119     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3120     { WM_NCCALCSIZE, sent|wparam, 1 },
3121     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3122     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
3123 
3124      /* in MDI frame */
3125     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3126     { WM_NCCALCSIZE, sent|wparam, 1 },
3127     { 0x0093, sent|defwinproc|optional },
3128     { 0x0093, sent|defwinproc|optional },
3129     { 0x0093, sent|defwinproc|optional },
3130     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3131     { WM_MOVE, sent|defwinproc },
3132     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3133 
3134      /* in MDI client */
3135     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3136     { WM_NCCALCSIZE, sent|wparam, 1 },
3137     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3138     { WM_SIZE, sent|wparam, SIZE_RESTORED },
3139 
3140      /* in MDI child */
3141     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3142     { WM_NCCALCSIZE, sent|wparam, 1 },
3143     { 0x0093, sent|optional },
3144     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3145     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3146 
3147     { 0x0093, sent|optional },
3148     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3149     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3150     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
3151     { 0x0093, sent|defwinproc|optional },
3152     { 0x0093, sent|defwinproc|optional },
3153     { 0x0093, sent|defwinproc|optional },
3154     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3155     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3156 
3157     { 0 }
3158 };
3159 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
3160 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
3161     { HCBT_CREATEWND, hook },
3162     { WM_GETMINMAXINFO, sent },
3163     { WM_NCCREATE, sent },
3164     { WM_NCCALCSIZE, sent|wparam, 0 },
3165     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
3166     { WM_CREATE, sent },
3167     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3168     { WM_SIZE, sent|wparam, SIZE_RESTORED },
3169     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOZORDER }, /* MDI frame */
3170     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI frame */
3171     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOZORDER }, /* MDI frame */
3172     { WM_MOVE, sent },
3173     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3174     { WM_GETMINMAXINFO, sent },
3175     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3176     { WM_GETMINMAXINFO, sent|defwinproc },
3177     { WM_NCCALCSIZE, sent|wparam, 1 },
3178     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_STATECHANGED },
3179     { WM_MOVE, sent|defwinproc },
3180     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3181      /* in MDI frame */
3182     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3183     { WM_NCCALCSIZE, sent|wparam, 1 },
3184     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3185     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3186     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
3187     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3188     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3189     /* Win2k sends wparam set to
3190      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3191      * while Win9x doesn't bother to set child window id according to
3192      * CLIENTCREATESTRUCT.idFirstChild
3193      */
3194     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3195     { 0 }
3196 };
3197 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
3198 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
3199     { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
3200     { HCBT_SYSCOMMAND, hook },
3201     { WM_CLOSE, sent|defwinproc },
3202     { WM_MDIDESTROY, sent }, /* in MDI client */
3203 
3204     /* bring the 1st MDI child to top */
3205     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
3206     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
3207 
3208     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3209 
3210     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
3211     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
3212     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
3213 
3214     /* maximize the 1st MDI child */
3215     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3216     { WM_GETMINMAXINFO, sent|defwinproc },
3217     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED },
3218     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
3219     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
3220     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3221     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3222 
3223     /* restore the 2nd MDI child */
3224     { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
3225     { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
3226     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
3227     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
3228 
3229     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3230 
3231     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3232     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3233 
3234     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3235 
3236     { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
3237      /* in MDI frame */
3238     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3239     { WM_NCCALCSIZE, sent|wparam, 1 },
3240     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3241     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3242     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3243 
3244     /* bring the 1st MDI child to top */
3245     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3246     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3247     { HCBT_SETFOCUS, hook },
3248     { WM_KILLFOCUS, sent|defwinproc },
3249     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
3250     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3251     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3252     { WM_SETFOCUS, sent }, /* in MDI client */
3253     { HCBT_SETFOCUS, hook },
3254     { WM_KILLFOCUS, sent }, /* in MDI client */
3255     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3256     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3257     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3258     { WM_SETFOCUS, sent|defwinproc },
3259     { WM_MDIACTIVATE, sent|defwinproc },
3260     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3261 
3262     /* apparently ShowWindow(SW_SHOW) on an MDI client */
3263     { WM_SHOWWINDOW, sent|wparam, 1 },
3264     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3265     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3266     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3267     { WM_MDIREFRESHMENU, sent },
3268 
3269     { HCBT_DESTROYWND, hook },
3270     /* Win2k sends wparam set to
3271      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3272      * while Win9x doesn't bother to set child window id according to
3273      * CLIENTCREATESTRUCT.idFirstChild
3274      */
3275     { 0x0090, sent|defwinproc|optional },
3276     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3277     { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
3278     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3279     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3280     { WM_ERASEBKGND, sent|parent|optional },
3281     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3282 
3283     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
3284     { WM_DESTROY, sent|defwinproc },
3285     { WM_NCDESTROY, sent|defwinproc },
3286     { 0 }
3287 };
3288 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
3289 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
3290     { WM_MDIDESTROY, sent }, /* in MDI client */
3291     { WM_SHOWWINDOW, sent|wparam, 0 },
3292     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3293     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3294     { WM_ERASEBKGND, sent|parent|optional },
3295     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3296 
3297     { HCBT_SETFOCUS, hook },
3298     { WM_KILLFOCUS, sent },
3299     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3300     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3301     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3302     { WM_SETFOCUS, sent }, /* in MDI client */
3303     { HCBT_SETFOCUS, hook },
3304     { WM_KILLFOCUS, sent }, /* in MDI client */
3305     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3306     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3307     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3308     { WM_SETFOCUS, sent },
3309 
3310      /* in MDI child */
3311     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3312     { WM_NCCALCSIZE, sent|wparam, 1 },
3313     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3314     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3315 
3316      /* in MDI frame */
3317     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3318     { WM_NCCALCSIZE, sent|wparam, 1 },
3319     { 0x0093, sent|defwinproc|optional },
3320     { 0x0093, sent|defwinproc|optional },
3321     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3322     { WM_MOVE, sent|defwinproc },
3323     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3324 
3325      /* in MDI client */
3326     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3327     { WM_NCCALCSIZE, sent|wparam, 1 },
3328     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3329     { WM_SIZE, sent|wparam, SIZE_RESTORED },
3330 
3331      /* in MDI child */
3332     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3333     { WM_NCCALCSIZE, sent|wparam, 1 },
3334     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3335     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3336 
3337      /* in MDI child */
3338     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3339     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3340     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3341     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3342 
3343      /* in MDI frame */
3344     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3345     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3346     { 0x0093, sent|defwinproc|optional },
3347     { 0x0093, sent|defwinproc|optional },
3348     { 0x0093, sent|defwinproc|optional },
3349     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3350     { WM_MOVE, sent|defwinproc },
3351     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3352 
3353      /* in MDI client */
3354     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3355     { WM_NCCALCSIZE, sent|wparam, 1 },
3356     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3357     { WM_SIZE, sent|wparam, SIZE_RESTORED },
3358 
3359      /* in MDI child */
3360     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3361     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3362     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3363     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3364     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3365     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3366 
3367     { 0x0093, sent|defwinproc|optional },
3368     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
3369     { 0x0093, sent|defwinproc|optional },
3370     { 0x0093, sent|defwinproc|optional },
3371     { 0x0093, sent|defwinproc|optional },
3372     { 0x0093, sent|optional },
3373 
3374     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3375     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3376     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3377     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3378     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3379 
3380      /* in MDI frame */
3381     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3382     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3383     { 0x0093, sent|defwinproc|optional },
3384     { 0x0093, sent|defwinproc|optional },
3385     { 0x0093, sent|defwinproc|optional },
3386     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3387     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3388     { 0x0093, sent|optional },
3389 
3390     { WM_NCACTIVATE, sent|wparam, 0 },
3391     { WM_MDIACTIVATE, sent },
3392 
3393     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
3394     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
3395     { WM_NCCALCSIZE, sent|wparam, 1 },
3396 
3397     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3398 
3399     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3400     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3401     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3402 
3403      /* in MDI child */
3404     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3405     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3406     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3407     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3408 
3409      /* in MDI frame */
3410     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3411     { WM_NCCALCSIZE, sent|wparam, 1 },
3412     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3413     { WM_MOVE, sent|defwinproc },
3414     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3415 
3416      /* in MDI client */
3417     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3418     { WM_NCCALCSIZE, sent|wparam, 1 },
3419     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3420     { WM_SIZE, sent|wparam, SIZE_RESTORED },
3421     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3422     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
3423     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3424     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3425     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3426 
3427     { HCBT_SETFOCUS, hook },
3428     { WM_KILLFOCUS, sent },
3429     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3430     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3431     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3432     { WM_SETFOCUS, sent }, /* in MDI client */
3433 
3434     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
3435 
3436     { HCBT_DESTROYWND, hook },
3437     /* Win2k sends wparam set to
3438      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3439      * while Win9x doesn't bother to set child window id according to
3440      * CLIENTCREATESTRUCT.idFirstChild
3441      */
3442     { 0x0090, sent|optional },
3443     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3444 
3445     { WM_SHOWWINDOW, sent|wparam, 0 },
3446     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3447     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3448     { WM_ERASEBKGND, sent|parent|optional },
3449     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3450 
3451     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
3452     { WM_DESTROY, sent },
3453     { WM_NCDESTROY, sent },
3454     { 0 }
3455 };
3456 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
3457 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
3458     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3459     { WM_GETMINMAXINFO, sent },
3460     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3461     { WM_NCCALCSIZE, sent|wparam, 1 },
3462     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3463     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3464 
3465     { WM_WINDOWPOSCHANGING, sent|wparam|optional|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3466     { WM_NCACTIVATE, sent|wparam|optional|defwinproc, 1 },
3467     { HCBT_SETFOCUS, hook|optional },
3468     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3469     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3470     { WM_SETFOCUS, sent|optional }, /* in MDI client */
3471     { HCBT_SETFOCUS, hook|optional },
3472     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3473     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3474     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3475     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3476     { WM_SETFOCUS, sent|optional|defwinproc },
3477     { WM_MDIACTIVATE, sent|optional|defwinproc },
3478     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3479     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3480      /* in MDI frame */
3481     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3482     { WM_NCCALCSIZE, sent|wparam, 1 },
3483     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3484     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3485     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3486     { 0 }
3487 };
3488 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
3489 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
3490     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3491     { WM_GETMINMAXINFO, sent },
3492     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
3493     { WM_GETMINMAXINFO, sent|defwinproc },
3494     { WM_NCCALCSIZE, sent|wparam, 1 },
3495     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3496     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3497 
3498     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3499     { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
3500     { HCBT_SETFOCUS, hook|optional },
3501     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3502     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3503     { WM_SETFOCUS, sent|optional }, /* in MDI client */
3504     { HCBT_SETFOCUS, hook|optional },
3505     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3506     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3507     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3508     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3509     { WM_SETFOCUS, sent|defwinproc|optional },
3510     { WM_MDIACTIVATE, sent|defwinproc|optional },
3511     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3512     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3513     { 0 }
3514 };
3515 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
3516 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
3517     { WM_MDIMAXIMIZE, sent }, /* in MDI client */
3518     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3519     { WM_GETMINMAXINFO, sent },
3520     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3521     { WM_GETMINMAXINFO, sent|defwinproc },
3522     { WM_NCCALCSIZE, sent|wparam, 1 },
3523     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
3524     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3525     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
3526     { WM_MOVE, sent|defwinproc },
3527     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3528 
3529     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3530     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3531     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3532     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3533     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3534     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3535      /* in MDI frame */
3536     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3537     { WM_NCCALCSIZE, sent|wparam, 1 },
3538     { 0x0093, sent|defwinproc|optional },
3539     { 0x0094, sent|defwinproc|optional },
3540     { 0x0094, sent|defwinproc|optional },
3541     { 0x0094, sent|defwinproc|optional },
3542     { 0x0094, sent|defwinproc|optional },
3543     { 0x0093, sent|defwinproc|optional },
3544     { 0x0093, sent|defwinproc|optional },
3545     { 0x0091, sent|defwinproc|optional },
3546     { 0x0092, sent|defwinproc|optional },
3547     { 0x0092, sent|defwinproc|optional },
3548     { 0x0092, sent|defwinproc|optional },
3549     { 0x0092, sent|defwinproc|optional },
3550     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3551     { WM_MOVE, sent|defwinproc },
3552     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3553     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
3554      /* in MDI client */
3555     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3556     { WM_NCCALCSIZE, sent|wparam, 1 },
3557     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3558     { WM_SIZE, sent|wparam, SIZE_RESTORED },
3559      /* in MDI child */
3560     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3561     { WM_GETMINMAXINFO, sent|defwinproc },
3562     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3563     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3564     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3565     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
3566     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3567     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3568     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3569     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3570      /* in MDI frame */
3571     { 0x0093, sent|optional },
3572     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3573     { 0x0093, sent|defwinproc|optional },
3574     { 0x0093, sent|defwinproc|optional },
3575     { 0x0093, sent|defwinproc|optional },
3576     { 0x0091, sent|defwinproc|optional },
3577     { 0x0092, sent|defwinproc|optional },
3578     { 0x0092, sent|defwinproc|optional },
3579     { 0x0092, sent|defwinproc|optional },
3580     { 0x0092, sent|defwinproc|optional },
3581     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3582     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3583     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3584     { 0 }
3585 };
3586 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
3587 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
3588     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3589     { WM_GETMINMAXINFO, sent },
3590     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3591     { WM_NCCALCSIZE, sent|wparam, 1 },
3592     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3593     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3594     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3595      /* in MDI frame */
3596     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3597     { WM_NCCALCSIZE, sent|wparam, 1 },
3598     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3599     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3600     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3601     { 0 }
3602 };
3603 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
3604 static const struct message WmRestoreMDIchildVisibleSeq[] = {
3605     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3606     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3607     { WM_NCCALCSIZE, sent|wparam, 1 },
3608     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3609     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3610     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3611      /* in MDI frame */
3612     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3613     { WM_NCCALCSIZE, sent|wparam, 1 },
3614     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3615     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3616     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3617     { 0 }
3618 };
3619 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
3620 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
3621     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3622     { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
3623     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3624     { WM_NCCALCSIZE, sent|wparam, 1 },
3625     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3626     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3627     { WM_MOVE, sent|defwinproc },
3628     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3629     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3630     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3631     { HCBT_SETFOCUS, hook },
3632     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3633     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
3634     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3635     { WM_SETFOCUS, sent },
3636     { 0 }
3637 };
3638 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
3639 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
3640     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
3641     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3642     { WM_NCCALCSIZE, sent|wparam, 1 },
3643     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3644     { WM_MOVE, sent|defwinproc },
3645     { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
3646     { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
3647     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3648     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3649     /* FIXME: Wine creates an icon/title window while Windows doesn't */
3650     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */
3651     { 0 }
3652 };
3653 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
3654 static const struct message WmRestoreMDIchildInvisibleSeq[] = {
3655     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3656     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED  },
3657     { WM_NCCALCSIZE, sent|wparam, 1 },
3658     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3659     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3660     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3661     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3662      /* in MDI frame */
3663     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3664     { WM_NCCALCSIZE, sent|wparam, 1 },
3665     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3666     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3667     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3668     { 0 }
3669 };
3670 
3671 static HWND mdi_client;
3672 static WNDPROC old_mdi_client_proc;
3673 
3674 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3675 {
3676     struct recvd_message msg;
3677 
3678     /* do not log painting messages */
3679     if (message != WM_PAINT &&
3680         message != WM_NCPAINT &&
3681         message != WM_SYNCPAINT &&
3682         message != WM_ERASEBKGND &&
3683         message != WM_NCHITTEST &&
3684         message != WM_GETTEXT &&
3685         message != WM_MDIGETACTIVE &&
3686         !ignore_message( message ))
3687     {
3688         msg.hwnd = hwnd;
3689         msg.message = message;
3690         msg.flags = sent|wparam|lparam;
3691         msg.wParam = wParam;
3692         msg.lParam = lParam;
3693         msg.descr = "mdi client";
3694         add_message(&msg);
3695     }
3696 
3697     return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
3698 }
3699 
3700 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3701 {
3702     static LONG defwndproc_counter = 0;
3703     LRESULT ret;
3704     struct recvd_message msg;
3705 
3706     /* do not log painting messages */
3707     if (message != WM_PAINT &&
3708         message != WM_NCPAINT &&
3709         message != WM_SYNCPAINT &&
3710         message != WM_ERASEBKGND &&
3711         message != WM_NCHITTEST &&
3712         message != WM_GETTEXT &&
3713         !ignore_message( message ))
3714     {
3715         switch (message)
3716         {
3717             case WM_MDIACTIVATE:
3718             {
3719                 HWND active, client = GetParent(hwnd);
3720 
3721                 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
3722 
3723                 if (hwnd == (HWND)lParam) /* if we are being activated */
3724                     ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
3725                 else
3726                     ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
3727                 break;
3728             }
3729         }
3730 
3731         msg.hwnd = hwnd;
3732         msg.message = message;
3733         msg.flags = sent|wparam|lparam;
3734         if (defwndproc_counter) msg.flags |= defwinproc;
3735         msg.wParam = wParam;
3736         msg.lParam = lParam;
3737         msg.descr = "mdi child";
3738         add_message(&msg);
3739     }
3740 
3741     defwndproc_counter++;
3742     ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
3743     defwndproc_counter--;
3744 
3745     return ret;
3746 }
3747 
3748 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3749 {
3750     static LONG defwndproc_counter = 0;
3751     LRESULT ret;
3752     struct recvd_message msg;
3753 
3754     /* do not log painting messages */
3755     if (message != WM_PAINT &&
3756         message != WM_NCPAINT &&
3757         message != WM_SYNCPAINT &&
3758         message != WM_ERASEBKGND &&
3759         message != WM_NCHITTEST &&
3760         message != WM_GETTEXT &&
3761         !ignore_message( message ))
3762     {
3763         msg.hwnd = hwnd;
3764         msg.message = message;
3765         msg.flags = sent|wparam|lparam;
3766         if (defwndproc_counter) msg.flags |= defwinproc;
3767         msg.wParam = wParam;
3768         msg.lParam = lParam;
3769         msg.descr = "mdi frame";
3770         add_message(&msg);
3771     }
3772 
3773     defwndproc_counter++;
3774     ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
3775     defwndproc_counter--;
3776 
3777     return ret;
3778 }
3779 
3780 static BOOL mdi_RegisterWindowClasses(void)
3781 {
3782     WNDCLASSA cls;
3783 
3784     cls.style = 0;
3785     cls.lpfnWndProc = mdi_frame_wnd_proc;
3786     cls.cbClsExtra = 0;
3787     cls.cbWndExtra = 0;
3788     cls.hInstance = GetModuleHandleA(0);
3789     cls.hIcon = 0;
3790     cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
3791     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
3792     cls.lpszMenuName = NULL;
3793     cls.lpszClassName = "MDI_frame_class";
3794     if (!RegisterClassA(&cls)) return FALSE;
3795 
3796     cls.lpfnWndProc = mdi_child_wnd_proc;
3797     cls.lpszClassName = "MDI_child_class";
3798     if (!RegisterClassA(&cls)) return FALSE;
3799 
3800     if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
3801     old_mdi_client_proc = cls.lpfnWndProc;
3802     cls.hInstance = GetModuleHandleA(0);
3803     cls.lpfnWndProc = mdi_client_hook_proc;
3804     cls.lpszClassName = "MDI_client_class";
3805     if (!RegisterClassA(&cls)) assert(0);
3806 
3807     return TRUE;
3808 }
3809 
3810 static void test_mdi_messages(void)
3811 {
3812     MDICREATESTRUCTA mdi_cs;
3813     CLIENTCREATESTRUCT client_cs;
3814     HWND mdi_frame, mdi_child, mdi_child2, active_child;
3815     BOOL zoomed;
3816     RECT rc;
3817     HMENU hMenu = CreateMenu();
3818     LONG val;
3819 
3820     if (!mdi_RegisterWindowClasses()) assert(0);
3821 
3822     flush_sequence();
3823 
3824     trace("creating MDI frame window\n");
3825     mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
3826                                 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
3827                                 WS_MAXIMIZEBOX | WS_VISIBLE,
3828                                 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
3829                                 GetDesktopWindow(), hMenu,
3830                                 GetModuleHandleA(0), NULL);
3831     assert(mdi_frame);
3832     ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
3833 
3834     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3835     ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
3836 
3837     trace("creating MDI client window\n");
3838     GetClientRect(mdi_frame, &rc);
3839     client_cs.hWindowMenu = 0;
3840     client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
3841     mdi_client = CreateWindowExA(0, "MDI_client_class",
3842                                  NULL,
3843                                  WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
3844                                  rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
3845                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3846     assert(mdi_client);
3847     SetWindowLongA(mdi_client, 0, 0xdeadbeef);
3848 
3849     ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
3850     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3851     ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
3852 
3853     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3854     ok(!active_child, "wrong active MDI child %p\n", active_child);
3855     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3856 
3857     SetFocus(0);
3858     flush_sequence();
3859 
3860     trace("creating invisible MDI child window\n");
3861     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3862                                 WS_CHILD,
3863                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3864                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3865     assert(mdi_child);
3866 
3867     flush_sequence();
3868     ShowWindow(mdi_child, SW_SHOWNORMAL);
3869     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
3870 
3871     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3872     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3873 
3874     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3875     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3876 
3877     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3878     ok(!active_child, "wrong active MDI child %p\n", active_child);
3879     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3880 
3881     ShowWindow(mdi_child, SW_HIDE);
3882     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
3883     flush_sequence();
3884 
3885     ShowWindow(mdi_child, SW_SHOW);
3886     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
3887 
3888     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3889     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3890 
3891     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3892     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3893 
3894     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3895     ok(!active_child, "wrong active MDI child %p\n", active_child);
3896     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3897 
3898     DestroyWindow(mdi_child);
3899     flush_sequence();
3900 
3901     trace("creating visible MDI child window\n");
3902     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3903                                 WS_CHILD | WS_VISIBLE,
3904                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3905                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3906     assert(mdi_child);
3907     ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
3908 
3909     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3910     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3911 
3912     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3913     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3914 
3915     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3916     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3917     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3918     flush_sequence();
3919 
3920     DestroyWindow(mdi_child);
3921     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3922 
3923     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3924     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3925 
3926     /* Win2k: MDI client still returns a just destroyed child as active
3927      * Win9x: MDI client returns 0
3928      */
3929     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3930     ok(active_child == mdi_child || /* win2k */
3931        !active_child, /* win9x */
3932        "wrong active MDI child %p\n", active_child);
3933     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3934 
3935     flush_sequence();
3936 
3937     trace("creating invisible MDI child window\n");
3938     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3939                                 WS_CHILD,
3940                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3941                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3942     assert(mdi_child2);
3943     ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
3944 
3945     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
3946     ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
3947 
3948     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3949     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3950 
3951     /* Win2k: MDI client still returns a just destroyed child as active
3952      * Win9x: MDI client returns mdi_child2
3953      */
3954     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3955     ok(active_child == mdi_child || /* win2k */
3956        active_child == mdi_child2, /* win9x */
3957        "wrong active MDI child %p\n", active_child);
3958     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3959     flush_sequence();
3960 
3961     ShowWindow(mdi_child2, SW_MAXIMIZE);
3962     ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
3963 
3964     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3965     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3966 
3967     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3968     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3969     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3970     flush_sequence();
3971 
3972     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3973     ok(GetFocus() == mdi_child2 || /* win2k */
3974        GetFocus() == 0, /* win9x */
3975        "wrong focus window %p\n", GetFocus());
3976 
3977     SetFocus(0);
3978     flush_sequence();
3979 
3980     ShowWindow(mdi_child2, SW_HIDE);
3981     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3982 
3983     ShowWindow(mdi_child2, SW_RESTORE);
3984     ok_sequence(WmRestoreMDIchildInvisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
3985     flush_sequence();
3986 
3987     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3988     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3989 
3990     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3991     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3992     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3993     flush_sequence();
3994 
3995     SetFocus(0);
3996     flush_sequence();
3997 
3998     ShowWindow(mdi_child2, SW_HIDE);
3999     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
4000 
4001     ShowWindow(mdi_child2, SW_SHOW);
4002     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
4003 
4004     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4005     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4006 
4007     ShowWindow(mdi_child2, SW_MAXIMIZE);
4008     ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
4009 
4010     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4011     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4012 
4013     ShowWindow(mdi_child2, SW_RESTORE);
4014     ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
4015 
4016     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4017     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4018 
4019     ShowWindow(mdi_child2, SW_MINIMIZE);
4020     ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", TRUE);
4021 
4022     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4023     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4024 
4025     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4026     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4027     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4028     flush_sequence();
4029 
4030     ShowWindow(mdi_child2, SW_RESTORE);
4031     ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", FALSE);
4032 
4033     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4034     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4035 
4036     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4037     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4038     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4039     flush_sequence();
4040 
4041     SetFocus(0);
4042     flush_sequence();
4043 
4044     ShowWindow(mdi_child2, SW_HIDE);
4045     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
4046 
4047     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4048     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4049 
4050     DestroyWindow(mdi_child2);
4051     ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
4052 
4053     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4054     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4055 
4056     trace("Testing WM_CHILDACTIVATE\n");
4057 
4058     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4059                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_DISABLED,
4060                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4061                                 mdi_client, 0, GetModuleHandleA(0), NULL);
4062 
4063     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4064                                  WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX,
4065                                  0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4066                                  mdi_client, 0, GetModuleHandleA(0), NULL);
4067 
4068     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4069     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4070     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4071 
4072     flush_sequence();
4073     SendMessageW(mdi_child, WM_CHILDACTIVATE, 0, 0);
4074     ok_sequence(WmChildActivateDisabledWindowSeq, "WM_CHILDACTIVATE sent to disabled window", FALSE);
4075 
4076     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4077     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4078     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4079     flush_sequence();
4080 
4081     EnableWindow(mdi_child, TRUE);
4082 
4083     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4084     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4085     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4086 
4087     flush_sequence();
4088     SendMessageW(mdi_child, WM_CHILDACTIVATE, 0, 0);
4089     ok_sequence(WmChildActivateWindowSeq, "WM_CHILDACTIVATE sent to enabled window", FALSE);
4090 
4091     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4092     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4093     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4094     flush_sequence();
4095 
4096     DestroyWindow(mdi_child);
4097     DestroyWindow(mdi_child2);
4098     flush_sequence();
4099 
4100     /* test for maximized MDI children */
4101     trace("creating maximized visible MDI child window 1\n");
4102     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4103                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4104                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4105                                 mdi_client, 0, GetModuleHandleA(0), NULL);
4106     assert(mdi_child);
4107     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
4108     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4109 
4110     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4111     ok(GetFocus() == mdi_child || /* win2k */
4112        GetFocus() == 0, /* win9x */
4113        "wrong focus window %p\n", GetFocus());
4114 
4115     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4116     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4117     ok(zoomed, "wrong zoomed state %d\n", zoomed);
4118     flush_sequence();
4119 
4120     trace("creating maximized visible MDI child window 2\n");
4121     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4122                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4123                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4124                                 mdi_client, 0, GetModuleHandleA(0), NULL);
4125     assert(mdi_child2);
4126     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
4127     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
4128     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4129 
4130     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4131     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4132 
4133     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4134     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4135     ok(zoomed, "wrong zoomed state %d\n", zoomed);
4136     flush_sequence();
4137 
4138     trace("destroying maximized visible MDI child window 2\n");
4139     DestroyWindow(mdi_child2);
4140     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
4141 
4142     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4143 
4144     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4145     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4146 
4147     /* Win2k: MDI client still returns a just destroyed child as active
4148      * Win9x: MDI client returns 0
4149      */
4150     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4151     ok(active_child == mdi_child2 || /* win2k */
4152        !active_child, /* win9x */
4153        "wrong active MDI child %p\n", active_child);
4154     flush_sequence();
4155 
4156     ShowWindow(mdi_child, SW_MAXIMIZE);
4157     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4158     flush_sequence();
4159 
4160     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4161     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4162 
4163     trace("re-creating maximized visible MDI child window 2\n");
4164     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4165                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4166                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4167                                 mdi_client, 0, GetModuleHandleA(0), NULL);
4168     assert(mdi_child2);
4169     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
4170     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
4171     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4172 
4173     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4174     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4175 
4176     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4177     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4178     ok(zoomed, "wrong zoomed state %d\n", zoomed);
4179     flush_sequence();
4180 
4181     SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
4182     ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
4183     ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
4184 
4185     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4186     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4187     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4188 
4189     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4190     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4191     ok(zoomed, "wrong zoomed state %d\n", zoomed);
4192     flush_sequence();
4193 
4194     DestroyWindow(mdi_child);
4195     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
4196 
4197     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4198     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4199 
4200     /* Win2k: MDI client still returns a just destroyed child as active
4201      * Win9x: MDI client returns 0
4202      */
4203     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4204     ok(active_child == mdi_child || /* win2k */
4205        !active_child, /* win9x */
4206        "wrong active MDI child %p\n", active_child);
4207     flush_sequence();
4208 
4209     trace("creating maximized invisible MDI child window\n");
4210     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4211                                 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
4212                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4213                                 mdi_client, 0, GetModuleHandleA(0), NULL);
4214     assert(mdi_child2);
4215     ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", FALSE);
4216     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
4217     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
4218     ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
4219 
4220     /* Win2k: MDI client still returns a just destroyed child as active
4221      * Win9x: MDI client returns 0
4222      */
4223     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4224     ok(active_child == mdi_child || /* win2k */
4225        !active_child || active_child == mdi_child2, /* win9x */
4226        "wrong active MDI child %p\n", active_child);
4227     flush_sequence();
4228 
4229     trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
4230     ShowWindow(mdi_child2, SW_MAXIMIZE);
4231     ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
4232     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
4233     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4234     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
4235 
4236     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4237     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4238     ok(zoomed, "wrong zoomed state %d\n", zoomed);
4239     flush_sequence();
4240 
4241     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
4242     flush_sequence();
4243 
4244     /* end of test for maximized MDI children */
4245     SetFocus(0);
4246     flush_sequence();
4247     trace("creating maximized visible MDI child window 1(Switch test)\n");
4248     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4249                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4250                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4251                                 mdi_client, 0, GetModuleHandleA(0), NULL);
4252     assert(mdi_child);
4253     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE);
4254     ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n");
4255 
4256     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
4257     ok(GetFocus() == mdi_child || /* win2k */
4258        GetFocus() == 0, /* win9x */
4259        "wrong focus window %p(Switch test)\n", GetFocus());
4260 
4261     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4262     ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
4263     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
4264     flush_sequence();
4265 
4266     trace("creating maximized visible MDI child window 2(Switch test)\n");
4267     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4268                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4269                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4270                                 mdi_client, 0, GetModuleHandleA(0), NULL);
4271     assert(mdi_child2);
4272     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child window (Switch test)", TRUE);
4273 
4274     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n");
4275     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized(Switch test)\n");
4276 
4277     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
4278     ok(GetFocus() == mdi_child2, "wrong focus window %p(Switch test)\n", GetFocus());
4279 
4280     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4281     ok(active_child == mdi_child2, "wrong active MDI child %p(Switch test)\n", active_child);
4282     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
4283     flush_sequence();
4284 
4285     trace("Switch child window.\n");
4286     SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0);
4287     ok_sequence(WmSwitchChild, "Child did not switch correctly", TRUE);
4288     trace("end of test for switch maximized MDI children\n");
4289     flush_sequence();
4290 
4291     /* Prepare for switching test of not maximized MDI children  */
4292     ShowWindow( mdi_child, SW_NORMAL );
4293     ok(!IsZoomed(mdi_child), "wrong zoomed state for %p(Switch test)\n", mdi_child);
4294     ok(!IsZoomed(mdi_child2), "wrong zoomed state for %p(Switch test)\n", mdi_child2);
4295     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
4296     ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
4297     flush_sequence();
4298 
4299     SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child2, 0);
4300     ok_sequence(WmSwitchNotMaximizedChild, "Not maximized child did not switch correctly", FALSE);
4301     trace("end of test for switch not maximized MDI children\n");
4302     flush_sequence();
4303 
4304     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
4305     flush_sequence();
4306 
4307     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
4308     flush_sequence();
4309 
4310     SetFocus(0);
4311     flush_sequence();
4312     /* end of tests for switch maximized/not maximized MDI children */
4313 
4314     mdi_cs.szClass = "MDI_child_Class";
4315     mdi_cs.szTitle = "MDI child";
4316     mdi_cs.hOwner = GetModuleHandleA(0);
4317     mdi_cs.x = 0;
4318     mdi_cs.y = 0;
4319     mdi_cs.cx = CW_USEDEFAULT;
4320     mdi_cs.cy = CW_USEDEFAULT;
4321     mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
4322     mdi_cs.lParam = 0;
4323     mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
4324     ok(mdi_child != 0, "MDI child creation failed\n");
4325     ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
4326 
4327     ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
4328 
4329     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4330     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4331 
4332     ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
4333     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4334     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4335 
4336     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4337     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4338     ok(zoomed, "wrong zoomed state %d\n", zoomed);
4339     flush_sequence();
4340 
4341     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
4342     ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
4343 
4344     ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
4345     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4346     ok(!active_child, "wrong active MDI child %p\n", active_child);
4347 
4348     SetFocus(0);
4349     flush_sequence();
4350 
4351     val = GetWindowLongA(mdi_client, 0);
4352     ok(val == 0xdeadbeef || broken(val == 0) /* >= Win Vista */, "Expected 0xdeadbeef, got 0x%x\n", val);
4353     DestroyWindow(mdi_client);
4354     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
4355 
4356     /* test maximization of MDI child with invisible parent */
4357     client_cs.hWindowMenu = 0;
4358     mdi_client = CreateWindowA("MDI_client_class",
4359                                  NULL,
4360                                  WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
4361                                  0, 0, 660, 430,
4362                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
4363     ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
4364 
4365     ShowWindow(mdi_client, SW_HIDE);
4366     ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
4367 
4368     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4369                                 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
4370                                 0, 0, 650, 440,
4371                                 mdi_client, 0, GetModuleHandleA(0), NULL);
4372     ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
4373 
4374     SendMessageA(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
4375     ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
4376     zoomed = IsZoomed(mdi_child);
4377     ok(zoomed, "wrong zoomed state %d\n", zoomed);
4378 
4379     ShowWindow(mdi_client, SW_SHOW);
4380     ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
4381 
4382     DestroyWindow(mdi_child);
4383     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
4384 
4385     /* end of test for maximization of MDI child with invisible parent */
4386 
4387     DestroyWindow(mdi_client);
4388     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
4389 
4390     DestroyWindow(mdi_frame);
4391     ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
4392 }
4393 /************************* End of MDI test **********************************/
4394 
4395 static void test_WM_SETREDRAW(HWND hwnd)
4396 {
4397     DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
4398 
4399     flush_events();
4400     flush_sequence();
4401 
4402     SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
4403     ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
4404 
4405     ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
4406     ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
4407 
4408     flush_sequence();
4409     SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
4410     ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
4411 
4412     ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4413     ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
4414 
4415     /* restore original WS_VISIBLE state */
4416     SetWindowLongA(hwnd, GWL_STYLE, style);
4417 
4418     flush_events();
4419     flush_sequence();
4420 }
4421 
4422 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4423 {
4424     struct recvd_message msg;
4425 
4426     if (ignore_message( message )) return 0;
4427 
4428     switch (message)
4429     {
4430 	/* ignore */
4431 	case WM_MOUSEMOVE:
4432 	case WM_NCMOUSEMOVE:
4433 	case WM_NCMOUSELEAVE:
4434 	case WM_SETCURSOR:
4435             return 0;
4436         case WM_NCHITTEST:
4437             return HTCLIENT;
4438     }
4439 
4440     msg.hwnd = hwnd;
4441     msg.message = message;
4442     msg.flags = sent|wparam|lparam;
4443     msg.wParam = wParam;
4444     msg.lParam = lParam;
4445     msg.descr = "dialog";
4446     add_message(&msg);
4447 
4448     if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
4449     if (message == WM_TIMER) EndDialog( hwnd, 0 );
4450     return 0;
4451 }
4452 
4453 static INT_PTR CALLBACK TestModalDlgProc2(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4454 {
4455     struct recvd_message msg;
4456 
4457     if (ignore_message( message )) return 0;
4458 
4459     switch (message)
4460     {
4461 	/* ignore */
4462 	case WM_MOUSEMOVE:
4463 	case WM_NCMOUSEMOVE:
4464 	case WM_NCMOUSELEAVE:
4465 	case WM_SETCURSOR:
4466             return 0;
4467         case WM_NCHITTEST:
4468             return HTCLIENT;
4469     }
4470 
4471     msg.hwnd = hwnd;
4472     msg.message = message;
4473     msg.flags = sent|wparam|lparam;
4474     msg.wParam = wParam;
4475     msg.lParam = lParam;
4476     msg.descr = "dialog";
4477     add_message(&msg);
4478 
4479     if (message == WM_INITDIALOG) EndDialog( hwnd, 0 );
4480     return 0;
4481 }
4482 
4483 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4484 {
4485     DWORD style, exstyle;
4486     INT xmin, xmax;
4487     BOOL ret;
4488 
4489     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4490     style = GetWindowLongA(hwnd, GWL_STYLE);
4491     /* do not be confused by WS_DLGFRAME set */
4492     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4493 
4494     if (clear) ok(style & clear, "style %08x should be set\n", clear);
4495     if (set) ok(!(style & set), "style %08x should not be set\n", set);
4496 
4497     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4498     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
4499     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4500         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
4501     else
4502         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
4503 
4504     style = GetWindowLongA(hwnd, GWL_STYLE);
4505     if (set) ok(style & set, "style %08x should be set\n", set);
4506     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4507 
4508     /* a subsequent call should do nothing */
4509     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4510     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
4511     ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4512 
4513     xmin = 0xdeadbeef;
4514     xmax = 0xdeadbeef;
4515     ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
4516     ok( ret, "GetScrollRange(%d) error %d\n", ctl, GetLastError());
4517     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4518     ok(xmin == min, "unexpected min scroll value %d\n", xmin);
4519     ok(xmax == max, "unexpected max scroll value %d\n", xmax);
4520 }
4521 
4522 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4523 {
4524     DWORD style, exstyle;
4525     SCROLLINFO si;
4526     BOOL ret;
4527 
4528     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4529     style = GetWindowLongA(hwnd, GWL_STYLE);
4530     /* do not be confused by WS_DLGFRAME set */
4531     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4532 
4533     if (clear) ok(style & clear, "style %08x should be set\n", clear);
4534     if (set) ok(!(style & set), "style %08x should not be set\n", set);
4535 
4536     si.cbSize = sizeof(si);
4537     si.fMask = SIF_RANGE;
4538     si.nMin = min;
4539     si.nMax = max;
4540     SetScrollInfo(hwnd, ctl, &si, TRUE);
4541     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4542         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
4543     else
4544         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
4545 
4546     style = GetWindowLongA(hwnd, GWL_STYLE);
4547     if (set) ok(style & set, "style %08x should be set\n", set);
4548     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4549 
4550     /* a subsequent call should do nothing */
4551     SetScrollInfo(hwnd, ctl, &si, TRUE);
4552     if (style & WS_HSCROLL)
4553         ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4554     else if (style & WS_VSCROLL)
4555         ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4556     else
4557         ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4558 
4559     si.fMask = SIF_PAGE;
4560     si.nPage = 5;
4561     SetScrollInfo(hwnd, ctl, &si, FALSE);
4562     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4563 
4564     si.fMask = SIF_POS;
4565     si.nPos = max - 1;
4566     SetScrollInfo(hwnd, ctl, &si, FALSE);
4567     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4568 
4569     si.fMask = SIF_RANGE;
4570     si.nMin = 0xdeadbeef;
4571     si.nMax = 0xdeadbeef;
4572     ret = GetScrollInfo(hwnd, ctl, &si);
4573     ok( ret, "GetScrollInfo error %d\n", GetLastError());
4574     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4575     ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
4576     ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
4577 }
4578 
4579 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
4580 static void test_scroll_messages(HWND hwnd)
4581 {
4582     SCROLLINFO si;
4583     INT min, max;
4584     BOOL ret;
4585 
4586     flush_events();
4587     flush_sequence();
4588 
4589     min = 0xdeadbeef;
4590     max = 0xdeadbeef;
4591     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4592     ok( ret, "GetScrollRange error %d\n", GetLastError());
4593     if (sequence->message != WmGetScrollRangeSeq[0].message)
4594         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4595     /* values of min and max are undefined */
4596     flush_sequence();
4597 
4598     ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
4599     ok( ret, "SetScrollRange error %d\n", GetLastError());
4600     if (sequence->message != WmSetScrollRangeSeq[0].message)
4601         trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4602     flush_sequence();
4603 
4604     min = 0xdeadbeef;
4605     max = 0xdeadbeef;
4606     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4607     ok( ret, "GetScrollRange error %d\n", GetLastError());
4608     if (sequence->message != WmGetScrollRangeSeq[0].message)
4609         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4610     /* values of min and max are undefined */
4611     flush_sequence();
4612 
4613     si.cbSize = sizeof(si);
4614     si.fMask = SIF_RANGE;
4615     si.nMin = 20;
4616     si.nMax = 160;
4617     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4618     if (sequence->message != WmSetScrollRangeSeq[0].message)
4619         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4620     flush_sequence();
4621 
4622     si.fMask = SIF_PAGE;
4623     si.nPage = 10;
4624     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4625     if (sequence->message != WmSetScrollRangeSeq[0].message)
4626         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4627     flush_sequence();
4628 
4629     si.fMask = SIF_POS;
4630     si.nPos = 20;
4631     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4632     if (sequence->message != WmSetScrollRangeSeq[0].message)
4633         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4634     flush_sequence();
4635 
4636     si.fMask = SIF_RANGE;
4637     si.nMin = 0xdeadbeef;
4638     si.nMax = 0xdeadbeef;
4639     ret = GetScrollInfo(hwnd, SB_CTL, &si);
4640     ok( ret, "GetScrollInfo error %d\n", GetLastError());
4641     if (sequence->message != WmGetScrollInfoSeq[0].message)
4642         trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4643     /* values of min and max are undefined */
4644     flush_sequence();
4645 
4646     /* set WS_HSCROLL */
4647     test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4648     /* clear WS_HSCROLL */
4649     test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4650 
4651     /* set WS_HSCROLL */
4652     test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4653     /* clear WS_HSCROLL */
4654     test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4655 
4656     /* set WS_VSCROLL */
4657     test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4658     /* clear WS_VSCROLL */
4659     test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4660 
4661     /* set WS_VSCROLL */
4662     test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4663     /* clear WS_VSCROLL */
4664     test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4665 }
4666 
4667 static void test_showwindow(void)
4668 {
4669     HWND hwnd, hchild;
4670     RECT rc;
4671 
4672     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4673                            100, 100, 200, 200, 0, 0, 0, NULL);
4674     ok (hwnd != 0, "Failed to create overlapped window\n");
4675     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4676                              0, 0, 10, 10, hwnd, 0, 0, NULL);
4677     ok (hchild != 0, "Failed to create child\n");
4678     flush_sequence();
4679 
4680     /* ShowWindow( SW_SHOWNA) for invisible top level window */
4681     trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
4682     ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4683     ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", FALSE);
4684 
4685     /* ShowWindow( SW_SHOWNA) for now visible top level window */
4686     trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
4687     ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4688     ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
4689     /* back to invisible */
4690     ShowWindow(hchild, SW_HIDE);
4691     ShowWindow(hwnd, SW_HIDE);
4692     flush_sequence();
4693     /* ShowWindow(SW_SHOWNA) with child and parent invisible */
4694     trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
4695     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4696     ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
4697     /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */
4698     ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
4699     flush_sequence();
4700     trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
4701     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4702     ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
4703     /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
4704     ShowWindow( hwnd, SW_SHOW);
4705     flush_sequence();
4706     trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
4707     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4708     ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
4709 
4710     /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
4711     ShowWindow( hchild, SW_HIDE);
4712     flush_sequence();
4713     trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
4714     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4715     ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
4716 
4717     SetCapture(hchild);
4718     ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
4719     DestroyWindow(hchild);
4720     ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
4721 
4722     DestroyWindow(hwnd);
4723     flush_sequence();
4724 
4725     /* Popup windows */
4726     /* Test 1:
4727      * 1. Create invisible maximized popup window.
4728      * 2. Move and resize it.
4729      * 3. Show it maximized.
4730      */
4731     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4732     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4733                            100, 100, 200, 200, 0, 0, 0, NULL);
4734     ok (hwnd != 0, "Failed to create popup window\n");
4735     ok(IsZoomed(hwnd), "window should be maximized\n");
4736     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4737 
4738     GetWindowRect(hwnd, &rc);
4739     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4740         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4741         "Invalid maximized size before ShowWindow %s\n", wine_dbgstr_rect( &rc ));
4742     /* Reset window's size & position */
4743     SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
4744     ok(IsZoomed(hwnd), "window should be maximized\n");
4745     flush_sequence();
4746 
4747     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4748     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4749     ok(IsZoomed(hwnd), "window should be maximized\n");
4750     ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
4751 
4752     GetWindowRect(hwnd, &rc);
4753     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4754         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4755         "Invalid maximized size after ShowWindow %s\n", wine_dbgstr_rect( &rc ));
4756     DestroyWindow(hwnd);
4757     flush_sequence();
4758 
4759     /* Test again, this time the NC_PAINT message */
4760     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4761                            100, 100, 200, 200, 0, 0, 0, NULL);
4762     ok (hwnd != 0, "Failed to create popup window\n");
4763     SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
4764     flush_sequence();
4765     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4766     ok_sequence(WmShowMaxPopupResizedSeq_todo,
4767             "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup TODO", TRUE);
4768     DestroyWindow(hwnd);
4769     flush_sequence();
4770 
4771     /* Test 2:
4772      * 1. Create invisible maximized popup window.
4773      * 2. Show it maximized.
4774      */
4775     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4776     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4777                            100, 100, 200, 200, 0, 0, 0, NULL);
4778     ok (hwnd != 0, "Failed to create popup window\n");
4779     ok(IsZoomed(hwnd), "window should be maximized\n");
4780     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4781 
4782     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4783     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4784     ok(IsZoomed(hwnd), "window should be maximized\n");
4785     ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
4786     DestroyWindow(hwnd);
4787     flush_sequence();
4788 
4789     /* Test 3:
4790      * 1. Create visible maximized popup window.
4791      */
4792     trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
4793     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
4794                            100, 100, 200, 200, 0, 0, 0, NULL);
4795     ok (hwnd != 0, "Failed to create popup window\n");
4796     ok(IsZoomed(hwnd), "window should be maximized\n");
4797     ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4798     DestroyWindow(hwnd);
4799     flush_sequence();
4800 
4801     /* Test 4:
4802      * 1. Create visible popup window.
4803      * 2. Maximize it.
4804      */
4805     trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
4806     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
4807                            100, 100, 200, 200, 0, 0, 0, NULL);
4808     ok (hwnd != 0, "Failed to create popup window\n");
4809     ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
4810     ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE);
4811 
4812     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
4813     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4814     ok(IsZoomed(hwnd), "window should be maximized\n");
4815     ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
4816     DestroyWindow(hwnd);
4817     flush_sequence();
4818 }
4819 
4820 static void test_sys_menu(void)
4821 {
4822     HWND hwnd;
4823     HMENU hmenu;
4824     UINT state;
4825 
4826     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4827                            100, 100, 200, 200, 0, 0, 0, NULL);
4828     ok (hwnd != 0, "Failed to create overlapped window\n");
4829 
4830     flush_sequence();
4831 
4832     /* test existing window without CS_NOCLOSE style */
4833     hmenu = GetSystemMenu(hwnd, FALSE);
4834     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4835 
4836     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4837     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4838     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4839 
4840     EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
4841     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4842 
4843     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4844     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4845     ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
4846 
4847     EnableMenuItem(hmenu, SC_CLOSE, 0);
4848     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4849 
4850     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4851     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4852     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4853 
4854     /* test whether removing WS_SYSMENU destroys a system menu */
4855     SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
4856     SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4857     flush_sequence();
4858     hmenu = GetSystemMenu(hwnd, FALSE);
4859     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4860 
4861     DestroyWindow(hwnd);
4862 
4863     /* test new window with CS_NOCLOSE style */
4864     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4865                            100, 100, 200, 200, 0, 0, 0, NULL);
4866     ok (hwnd != 0, "Failed to create overlapped window\n");
4867 
4868     hmenu = GetSystemMenu(hwnd, FALSE);
4869     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4870 
4871     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4872     ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4873 
4874     DestroyWindow(hwnd);
4875 
4876     /* test new window without WS_SYSMENU style */
4877     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
4878                            100, 100, 200, 200, 0, 0, 0, NULL);
4879     ok(hwnd != 0, "Failed to create overlapped window\n");
4880 
4881     hmenu = GetSystemMenu(hwnd, FALSE);
4882     ok(!hmenu, "GetSystemMenu error %d\n", GetLastError());
4883 
4884     DestroyWindow(hwnd);
4885 }
4886 
4887 /* For shown WS_OVERLAPPEDWINDOW */
4888 static const struct message WmSetIcon_1[] = {
4889     { WM_SETICON, sent },
4890     { 0x00AE, sent|defwinproc|optional }, /* XP */
4891     { WM_GETTEXT, sent|defwinproc|optional },
4892     { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
4893     { 0 }
4894 };
4895 
4896 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
4897 static const struct message WmSetIcon_2[] = {
4898     { WM_SETICON, sent },
4899     { 0 }
4900 };
4901 
4902 /* Sending undocumented 0x3B message with wparam = 0x8000000b */
4903 static const struct message WmInitEndSession[] = {
4904     { 0x003B, sent },
4905     { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4906     { 0 }
4907 };
4908 
4909 /* Sending undocumented 0x3B message with wparam = 0x0000000b */
4910 static const struct message WmInitEndSession_2[] = {
4911     { 0x003B, sent },
4912     { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4913     { 0 }
4914 };
4915 
4916 /* Sending undocumented 0x3B message with wparam = 0x80000008 */
4917 static const struct message WmInitEndSession_3[] = {
4918     { 0x003B, sent },
4919     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4920     { 0 }
4921 };
4922 
4923 /* Sending undocumented 0x3B message with wparam = 0x00000008 */
4924 static const struct message WmInitEndSession_4[] = {
4925     { 0x003B, sent },
4926     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4927     { 0 }
4928 };
4929 
4930 /* Sending undocumented 0x3B message with wparam = 0x80000001 */
4931 static const struct message WmInitEndSession_5[] = {
4932     { 0x003B, sent },
4933     { WM_ENDSESSION, sent|defwinproc/*|wparam*/|lparam, 1, ENDSESSION_LOGOFF },
4934     { 0 }
4935 };
4936 
4937 static const struct message WmOptionalPaint[] = {
4938     { WM_PAINT, sent|optional },
4939     { WM_NCPAINT, sent|beginpaint|optional },
4940     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4941     { WM_ERASEBKGND, sent|beginpaint|optional },
4942     { 0 }
4943 };
4944 
4945 static const struct message WmZOrder[] = {
4946     { WM_WINDOWPOSCHANGING, sent|wparam, 0, 0 },
4947     { WM_GETMINMAXINFO, sent|defwinproc|wparam, 0, 0 },
4948     { HCBT_ACTIVATE, hook },
4949     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
4950     { WM_WINDOWPOSCHANGING, sent|wparam, 3, 0 },
4951     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0 },
4952     { WM_GETTEXT, sent|optional },
4953     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
4954     { WM_ACTIVATEAPP, sent|wparam, 1, 0 },
4955     { WM_NCACTIVATE, sent|lparam, 1, 0 },
4956     { WM_GETTEXT, sent|defwinproc|optional },
4957     { WM_GETTEXT, sent|defwinproc|optional },
4958     { WM_ACTIVATE, sent|wparam|lparam, 1, 0 },
4959     { HCBT_SETFOCUS, hook },
4960     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
4961     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4962     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
4963     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
4964     { WM_GETTEXT, sent|optional },
4965     { WM_NCCALCSIZE, sent|optional },
4966     { 0 }
4967 };
4968 
4969 static void CALLBACK apc_test_proc(ULONG_PTR param)
4970 {
4971     /* nothing */
4972 }
4973 
4974 static void test_MsgWaitForMultipleObjects(HWND hwnd)
4975 {
4976     DWORD ret;
4977     MSG msg;
4978 
4979     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4980     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4981 
4982     PostMessageA(hwnd, WM_USER, 0, 0);
4983 
4984     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4985     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4986 
4987     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4988     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4989 
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     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4996     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4997 
4998     ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
4999     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5000 
5001     /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
5002     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5003     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
5004 
5005     PostMessageA(hwnd, WM_USER, 0, 0);
5006 
5007     /* new incoming message causes it to become signaled again */
5008     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5009     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
5010 
5011     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5012     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5013     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5014     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5015 
5016     /* MWMO_INPUTAVAILABLE should succeed even if the message was already seen */
5017     PostMessageA( hwnd, WM_USER, 0, 0 );
5018     ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
5019     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5020 
5021     ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_INPUTAVAILABLE );
5022     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5023 
5024     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5025     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5026 
5027     /* without MWMO_ALERTABLE the result is never WAIT_IO_COMPLETION */
5028     ret = QueueUserAPC( apc_test_proc, GetCurrentThread(), 0 );
5029     ok(ret, "QueueUserAPC failed %u\n", GetLastError());
5030 
5031     ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, 0 );
5032     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5033 
5034     /* but even with MWMO_ALERTABLE window events are preferred */
5035     PostMessageA( hwnd, WM_USER, 0, 0 );
5036 
5037     ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_ALERTABLE );
5038     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5039 
5040     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5041     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5042 
5043     /* the APC call is still queued */
5044     ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_ALERTABLE );
5045     ok(ret == WAIT_IO_COMPLETION, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5046 }
5047 
5048 static void test_WM_DEVICECHANGE(HWND hwnd)
5049 {
5050     DWORD ret;
5051     MSG msg;
5052     int i;
5053     static const WPARAM wparams[] = {0,
5054                                      DBT_DEVNODES_CHANGED,
5055                                      DBT_QUERYCHANGECONFIG,
5056                                      DBT_CONFIGCHANGED,
5057                                      DBT_CONFIGCHANGECANCELED,
5058                                      DBT_NO_DISK_SPACE,
5059                                      DBT_LOW_DISK_SPACE,
5060                                      DBT_CONFIGMGPRIVATE, /* 0x7fff */
5061                                      DBT_DEVICEARRIVAL,   /* 0x8000 */
5062                                      DBT_DEVICEQUERYREMOVE,
5063                                      DBT_DEVICEQUERYREMOVEFAILED,
5064                                      DBT_DEVICEREMOVEPENDING,
5065                                      DBT_DEVICEREMOVECOMPLETE,
5066                                      DBT_DEVICETYPESPECIFIC,
5067                                      DBT_CUSTOMEVENT};
5068 
5069     for (i = 0; i < sizeof(wparams)/sizeof(wparams[0]); i++)
5070     {
5071         SetLastError(0xdeadbeef);
5072         ret = PostMessageA(hwnd, WM_DEVICECHANGE, wparams[i], 0);
5073         if (wparams[i] & 0x8000)
5074         {
5075             ok(ret == FALSE, "PostMessage should returned %d\n", ret);
5076             ok(GetLastError() == ERROR_MESSAGE_SYNC_ONLY, "PostMessage error %08x\n", GetLastError());
5077         }
5078         else
5079         {
5080             ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5081             ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
5082             memset(&msg, 0, sizeof(msg));
5083             ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should succeed\n");
5084             ok(msg.message == WM_DEVICECHANGE, "got %04x instead of WM_DEVICECHANGE\n", msg.message);
5085         }
5086     }
5087 }
5088 
5089 static DWORD CALLBACK show_window_thread(LPVOID arg)
5090 {
5091    HWND hwnd = arg;
5092 
5093    /* function will not return if ShowWindow(SW_HIDE) calls SendMessage() */
5094    ok(ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow(SW_HIDE) expected FALSE\n");
5095 
5096    return 0;
5097 }
5098 
5099 /* Helper function to easier test SetWindowPos messages */
5100 #define test_msg_setpos( expected_list, flags, todo ) \
5101         test_msg_setpos_( (expected_list), (flags), (todo), __FILE__, __LINE__)
5102 static void test_msg_setpos_(const struct message *expected_list, UINT flags, BOOL todo, const char *file, int line)
5103 {
5104     HWND hwnd;
5105 
5106     flush_events();
5107     flush_sequence();
5108     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5109                              10, 10, 100, 100, NULL, 0, 0, NULL );
5110     ok (hwnd != 0, "Failed to create popup window\n");
5111     SetWindowPos(hwnd, NULL, 0, 0, 100, 100, flags);
5112     ok_sequence_(expected_list, "SetWindowPos:show_popup_first_show_window", todo, file, line);
5113     DestroyWindow(hwnd);
5114 }
5115 
5116 /* test if we receive the right sequence of messages */
5117 static void test_messages(void)
5118 {
5119     DWORD tid;
5120     HANDLE hthread;
5121     HWND hwnd, hparent, hchild;
5122     HWND hchild2, hbutton;
5123     HMENU hmenu;
5124     MSG msg;
5125     LRESULT res;
5126     POINT pos;
5127     BOOL ret;
5128 
5129     flush_sequence();
5130 
5131     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5132                            100, 100, 200, 200, 0, 0, 0, NULL);
5133     ok (hwnd != 0, "Failed to create overlapped window\n");
5134     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
5135 
5136     /* test ShowWindow(SW_HIDE) on a newly created invisible window */
5137     ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
5138     ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
5139 
5140     /* test WM_SETREDRAW on a not visible top level window */
5141     test_WM_SETREDRAW(hwnd);
5142 
5143     SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5144     flush_events();
5145     ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
5146     ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
5147 
5148     ok(GetActiveWindow() == hwnd, "window should be active\n");
5149     ok(GetFocus() == hwnd, "window should have input focus\n");
5150     ShowWindow(hwnd, SW_HIDE);
5151     flush_events();
5152     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5153 
5154     /* test ShowWindow(SW_HIDE) on a hidden window - single threaded */
5155     ok(ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow(SW_HIDE) expected FALSE\n");
5156     flush_events();
5157     ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5158 
5159     /* test ShowWindow(SW_HIDE) on a hidden window -  multi-threaded */
5160     hthread = CreateThread(NULL, 0, show_window_thread, hwnd, 0, &tid);
5161     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
5162     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5163     CloseHandle(hthread);
5164     flush_events();
5165     ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5166 
5167     ShowWindow(hwnd, SW_SHOW);
5168     flush_events();
5169     ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
5170 
5171     ShowWindow(hwnd, SW_HIDE);
5172     flush_events();
5173     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5174 
5175     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5176     flush_events();
5177     ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
5178     flush_sequence();
5179 
5180     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZE)
5181     {
5182         ShowWindow(hwnd, SW_RESTORE);
5183         flush_events();
5184         ok_sequence(WmShowRestoreMaxOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
5185         flush_sequence();
5186     }
5187 
5188     ShowWindow(hwnd, SW_MINIMIZE);
5189     flush_events();
5190     ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE);
5191     flush_sequence();
5192 
5193     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE)
5194     {
5195         ShowWindow(hwnd, SW_RESTORE);
5196         flush_events();
5197         ok_sequence(WmShowRestoreMinOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
5198         flush_sequence();
5199     }
5200 
5201     ShowWindow(hwnd, SW_SHOW);
5202     flush_events();
5203     ok_sequence(WmOptionalPaint, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
5204 
5205     SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5206     ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
5207     ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
5208     ok(GetActiveWindow() == hwnd, "window should still be active\n");
5209 
5210     /* test WM_SETREDRAW on a visible top level window */
5211     ShowWindow(hwnd, SW_SHOW);
5212     flush_events();
5213     test_WM_SETREDRAW(hwnd);
5214 
5215     trace("testing scroll APIs on a visible top level window %p\n", hwnd);
5216     test_scroll_messages(hwnd);
5217 
5218     /* test resizing and moving */
5219     SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
5220     ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
5221     flush_events();
5222     flush_sequence();
5223     SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
5224     ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
5225     flush_events();
5226     flush_sequence();
5227     SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER|SWP_NOACTIVATE );
5228     ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
5229     flush_events();
5230     flush_sequence();
5231 
5232     /* popups don't get WM_GETMINMAXINFO */
5233     SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
5234     SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
5235     flush_sequence();
5236     SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
5237     ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
5238 
5239     DestroyWindow(hwnd);
5240     ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
5241 
5242     /* Test if windows are correctly drawn when first shown */
5243 
5244     /* Visible, redraw */
5245     flush_events();
5246     flush_sequence();
5247     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5248                              10, 10, 100, 100, NULL, 0, 0, NULL );
5249     ok (hwnd != 0, "Failed to create popup window\n");
5250     RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
5251     ok_sequence(WmShowPopupFirstDrawSeq_1, "RedrawWindow:show_popup_first_draw_visible", FALSE);
5252     DestroyWindow(hwnd);
5253 
5254     /* Invisible, show, message */
5255     flush_events();
5256     flush_sequence();
5257     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5258                              10, 10, 100, 100, NULL, 0, 0, NULL );
5259     ok (hwnd != 0, "Failed to create popup window\n");
5260     ShowWindow(hwnd, SW_SHOW);
5261     SendMessageW(hwnd, WM_PAINT, 0, 0);
5262     ok_sequence(WmShowPopupFirstDrawSeq_1, "RedrawWindow:show_popup_first_draw_show", FALSE);
5263     DestroyWindow(hwnd);
5264 
5265     /* Invisible, show maximized, redraw */
5266     flush_events();
5267     flush_sequence();
5268     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5269                              10, 10, 100, 100, NULL, 0, 0, NULL );
5270     ok (hwnd != 0, "Failed to create popup window\n");
5271     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5272     RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
5273     ok_sequence(WmShowPopupFirstDrawSeq_2, "RedrawWindow:show_popup_first_draw_show_maximized", FALSE);
5274     DestroyWindow(hwnd);
5275 
5276     /* Test SetWindowPos */
5277     test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW, FALSE);
5278     test_msg_setpos(WmFirstDrawSetWindowPosSeq2, 0, FALSE);
5279     test_msg_setpos(WmFirstDrawSetWindowPosSeq3,
5280             SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER, FALSE);
5281 
5282     test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOSIZE, FALSE);
5283     test_msg_setpos(WmFirstDrawSetWindowPosSeq4, SWP_SHOWWINDOW | SWP_NOMOVE, FALSE);
5284     test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCLIENTSIZE, FALSE);
5285     test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCLIENTMOVE, FALSE);
5286     test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOZORDER, FALSE);
5287 
5288     test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE, FALSE);
5289     test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOCLIENTMOVE, FALSE);
5290     test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOCLIENTSIZE, FALSE);
5291     test_msg_setpos(WmFirstDrawSetWindowPosSeq5, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOMOVE, FALSE);
5292     test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOSIZE, FALSE);
5293     test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOZORDER, FALSE);
5294 
5295     test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS, FALSE);
5296     test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOCLIENTMOVE, FALSE);
5297     test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOCLIENTSIZE, FALSE);
5298     test_msg_setpos(WmFirstDrawSetWindowPosSeq4, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOMOVE, FALSE);
5299     test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOSIZE, FALSE);
5300     test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOZORDER, FALSE);
5301 
5302     test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW, FALSE);
5303     test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOCLIENTMOVE, FALSE);
5304     test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOCLIENTSIZE, FALSE);
5305     test_msg_setpos(WmFirstDrawSetWindowPosSeq5, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOMOVE, FALSE);
5306     test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOSIZE, FALSE);
5307     test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOZORDER, FALSE);
5308 
5309     /* Test SetWindowPos with child windows */
5310     flush_events();
5311     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5312                               100, 100, 200, 200, 0, 0, 0, NULL);
5313     ok (hparent != 0, "Failed to create parent window\n");
5314 
5315     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5316                              0, 0, 10, 10, hparent, 0, 0, NULL);
5317     ok (hchild != 0, "Failed to create child window\n");
5318     flush_sequence();
5319     SetWindowPos(hparent, NULL, 0, 0, 100, 100, SWP_SHOWWINDOW);
5320     ok_sequence(WmFirstDrawChildSeq1, /* Expect no messages for the child */
5321                 "SetWindowPos:show_popup_first_show_window_child1", FALSE);
5322     DestroyWindow(hchild);
5323     DestroyWindow(hparent);
5324 
5325     flush_events();
5326     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN,
5327                               100, 100, 200, 200, 0, 0, 0, NULL);
5328     ok (hparent != 0, "Failed to create parent window\n");
5329 
5330     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5331                              0, 0, 10, 10, hparent, 0, 0, NULL);
5332     ok (hchild != 0, "Failed to create child window\n");
5333     flush_sequence();
5334     SetWindowPos(hparent, NULL, 0, 0, 100, 100, SWP_SHOWWINDOW);
5335     ok_sequence(WmFirstDrawChildSeq2, /* Expect child to be redrawn */
5336                 "SetWindowPos:show_popup_first_show_window_child2", FALSE);
5337     DestroyWindow(hchild);
5338     DestroyWindow(hparent);
5339 
5340     /* Test message sequence for extreme position and size */
5341 
5342     flush_sequence();
5343     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5344                              -10, -10, 10000, 10000, NULL, 0, 0, NULL );
5345     ok (hwnd != 0, "Failed to create popup window\n");
5346     ok_sequence(WmShowPopupExtremeLocationSeq, "RedrawWindow:show_popup_extreme_location", TRUE);
5347     DestroyWindow(hwnd);
5348 
5349 
5350     /* Test child windows */
5351 
5352     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5353                               100, 100, 200, 200, 0, 0, 0, NULL);
5354     ok (hparent != 0, "Failed to create parent window\n");
5355     flush_sequence();
5356 
5357     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
5358                              0, 0, 10, 10, hparent, 0, 0, NULL);
5359     ok (hchild != 0, "Failed to create child window\n");
5360     ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
5361     DestroyWindow(hchild);
5362     flush_sequence();
5363 
5364     /* visible child window with a caption */
5365     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
5366                              WS_CHILD | WS_VISIBLE | WS_CAPTION,
5367                              0, 0, 10, 10, hparent, 0, 0, NULL);
5368     ok (hchild != 0, "Failed to create child window\n");
5369     ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
5370 
5371     trace("testing scroll APIs on a visible child window %p\n", hchild);
5372     test_scroll_messages(hchild);
5373 
5374     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5375     ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
5376 
5377     DestroyWindow(hchild);
5378     flush_sequence();
5379 
5380     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5381                              0, 0, 10, 10, hparent, 0, 0, NULL);
5382     ok (hchild != 0, "Failed to create child window\n");
5383     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
5384 
5385     hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
5386                                100, 100, 50, 50, hparent, 0, 0, NULL);
5387     ok (hchild2 != 0, "Failed to create child2 window\n");
5388     flush_sequence();
5389 
5390     hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
5391                               0, 100, 50, 50, hchild, 0, 0, NULL);
5392     ok (hbutton != 0, "Failed to create button window\n");
5393 
5394     /* test WM_SETREDRAW on a not visible child window */
5395     test_WM_SETREDRAW(hchild);
5396 
5397     ShowWindow(hchild, SW_SHOW);
5398     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5399 
5400     /* check parent messages too */
5401     log_all_parent_messages++;
5402     ShowWindow(hchild, SW_HIDE);
5403     ok_sequence(WmHideChildSeq2, "ShowWindow(SW_HIDE):child", FALSE);
5404     log_all_parent_messages--;
5405 
5406     ShowWindow(hchild, SW_SHOW);
5407     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5408 
5409     ShowWindow(hchild, SW_HIDE);
5410     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
5411 
5412     ShowWindow(hchild, SW_SHOW);
5413     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5414 
5415     /* test WM_SETREDRAW on a visible child window */
5416     test_WM_SETREDRAW(hchild);
5417 
5418     log_all_parent_messages++;
5419     MoveWindow(hchild, 10, 10, 20, 20, TRUE);
5420     ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
5421     log_all_parent_messages--;
5422 
5423     ShowWindow(hchild, SW_HIDE);
5424     flush_sequence();
5425     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5426     ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
5427 
5428     ShowWindow(hchild, SW_HIDE);
5429     flush_sequence();
5430     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
5431     ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
5432 
5433     /* DestroyWindow sequence below expects that a child has focus */
5434     SetFocus(hchild);
5435     flush_sequence();
5436 
5437     DestroyWindow(hchild);
5438     ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
5439     DestroyWindow(hchild2);
5440     DestroyWindow(hbutton);
5441 
5442     flush_sequence();
5443     hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
5444                              0, 0, 100, 100, hparent, 0, 0, NULL);
5445     ok (hchild != 0, "Failed to create child popup window\n");
5446     ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
5447     DestroyWindow(hchild);
5448 
5449     /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
5450     flush_sequence();
5451     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
5452                              0, 0, 100, 100, hparent, 0, 0, NULL);
5453     ok (hchild != 0, "Failed to create popup window\n");
5454     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
5455     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5456     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
5457     flush_sequence();
5458     ShowWindow(hchild, SW_SHOW);
5459     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
5460     flush_sequence();
5461     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5462     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
5463     flush_sequence();
5464     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5465     ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
5466     DestroyWindow(hchild);
5467 
5468     /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
5469      * changes nothing in message sequences.
5470      */
5471     flush_sequence();
5472     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5473                              0, 0, 100, 100, hparent, 0, 0, NULL);
5474     ok (hchild != 0, "Failed to create popup window\n");
5475     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
5476     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5477     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
5478     flush_sequence();
5479     ShowWindow(hchild, SW_SHOW);
5480     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
5481     flush_sequence();
5482     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5483     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
5484     DestroyWindow(hchild);
5485 
5486     flush_sequence();
5487     hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
5488                            0, 0, 100, 100, hparent, 0, 0, NULL);
5489     ok(hwnd != 0, "Failed to create custom dialog window\n");
5490     ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
5491 
5492     if(0) {
5493     trace("testing scroll APIs on a visible dialog %p\n", hwnd);
5494     test_scroll_messages(hwnd);
5495     }
5496 
5497     flush_sequence();
5498 
5499     test_def_id = TRUE;
5500     SendMessageA(hwnd, WM_NULL, 0, 0);
5501 
5502     flush_sequence();
5503     after_end_dialog = TRUE;
5504     EndDialog( hwnd, 0 );
5505     ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
5506 
5507     DestroyWindow(hwnd);
5508     after_end_dialog = FALSE;
5509     test_def_id = FALSE;
5510 
5511     ok(GetCursorPos(&pos), "GetCursorPos failed\n");
5512     ok(SetCursorPos(109, 109), "SetCursorPos failed\n");
5513 
5514     hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP|WS_CHILD,
5515                            0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
5516     ok(hwnd != 0, "Failed to create custom dialog window\n");
5517     flush_sequence();
5518     trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
5519     ShowWindow(hwnd, SW_SHOW);
5520     ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
5521 
5522     flush_events();
5523     flush_sequence();
5524     ret = DrawMenuBar(hwnd);
5525     ok(ret, "DrawMenuBar failed: %d\n", GetLastError());
5526     flush_events();
5527     ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
5528     ok(SetCursorPos(pos.x, pos.y), "SetCursorPos failed\n");
5529 
5530     DestroyWindow(hwnd);
5531 
5532     hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_CHILD|WS_VISIBLE,
5533             0, 0, 100, 100, hparent, 0, GetModuleHandleA(0), NULL);
5534     ok(hwnd != 0, "Failed to create custom dialog window\n");
5535     flush_events();
5536     flush_sequence();
5537     ret = DrawMenuBar(hwnd);
5538     ok(ret, "DrawMenuBar failed: %d\n", GetLastError());
5539     flush_events();
5540     ok_sequence(WmEmptySeq, "DrawMenuBar for a child window", FALSE);
5541 
5542     DestroyWindow(hwnd);
5543 
5544     flush_sequence();
5545     DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
5546     ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
5547 
5548     DestroyWindow(hparent);
5549     flush_sequence();
5550 
5551     /* Message sequence for SetMenu */
5552     ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a destroyed window\n");
5553     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "last error is %d\n", GetLastError());
5554     ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
5555 
5556     hmenu = CreateMenu();
5557     ok (hmenu != 0, "Failed to create menu\n");
5558     ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
5559     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5560                            100, 100, 200, 200, 0, hmenu, 0, NULL);
5561     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
5562     ok (SetMenu(hwnd, 0), "SetMenu\n");
5563     ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
5564     ok (SetMenu(hwnd, 0), "SetMenu\n");
5565     ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
5566     ShowWindow(hwnd, SW_SHOW);
5567     UpdateWindow( hwnd );
5568     flush_events();
5569     flush_sequence();
5570     ok (SetMenu(hwnd, 0), "SetMenu\n");
5571     ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
5572     ok (SetMenu(hwnd, hmenu), "SetMenu\n");
5573     ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
5574 
5575     UpdateWindow( hwnd );
5576     flush_events();
5577     flush_sequence();
5578     ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
5579     flush_events();
5580     ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
5581 
5582     DestroyWindow(hwnd);
5583     flush_sequence();
5584 
5585     /* Message sequence for EnableWindow */
5586     hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5587                               100, 100, 200, 200, 0, 0, 0, NULL);
5588     ok (hparent != 0, "Failed to create parent window\n");
5589     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5590                              0, 0, 10, 10, hparent, 0, 0, NULL);
5591     ok (hchild != 0, "Failed to create child window\n");
5592 
5593     SetFocus(hchild);
5594     flush_events();
5595     flush_sequence();
5596 
5597     EnableWindow(hparent, FALSE);
5598     ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
5599 
5600     EnableWindow(hparent, FALSE);
5601     ok_sequence(WmEnableWindowSeq_2, "EnableWindow(FALSE)", FALSE);
5602 
5603     EnableWindow(hparent, TRUE);
5604     ok_sequence(WmEnableWindowSeq_3, "EnableWindow(TRUE)", FALSE);
5605 
5606     EnableWindow(hparent, TRUE);
5607     ok_sequence(WmEnableWindowSeq_4, "EnableWindow(TRUE)", FALSE);
5608 
5609     flush_events();
5610     flush_sequence();
5611 
5612     test_MsgWaitForMultipleObjects(hparent);
5613     test_WM_DEVICECHANGE(hparent);
5614 
5615     /* the following test causes an exception in user.exe under win9x */
5616     if (!PostMessageW( hparent, WM_USER, 0, 0 ))
5617     {
5618         DestroyWindow(hparent);
5619         flush_sequence();
5620         return;
5621     }
5622     PostMessageW( hparent, WM_USER+1, 0, 0 );
5623     /* PeekMessage(NULL) fails, but still removes the message */
5624     SetLastError(0xdeadbeef);
5625     ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
5626     ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
5627         GetLastError() == 0xdeadbeef, /* NT4 */
5628         "last error is %d\n", GetLastError() );
5629     ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
5630     ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
5631 
5632     DestroyWindow(hchild);
5633     DestroyWindow(hparent);
5634     flush_sequence();
5635 
5636     /* Message sequences for WM_SETICON */
5637     trace("testing WM_SETICON\n");
5638     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
5639                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5640                            NULL, NULL, 0);
5641     ShowWindow(hwnd, SW_SHOW);
5642     UpdateWindow(hwnd);
5643     flush_events();
5644     flush_sequence();
5645     SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5646     ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
5647 
5648     ShowWindow(hwnd, SW_HIDE);
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 hidden window with caption", FALSE);
5653     DestroyWindow(hwnd);
5654     flush_sequence();
5655 
5656     hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
5657                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5658                            NULL, NULL, 0);
5659     ShowWindow(hwnd, SW_SHOW);
5660     UpdateWindow(hwnd);
5661     flush_events();
5662     flush_sequence();
5663     SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5664     ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
5665 
5666     ShowWindow(hwnd, SW_HIDE);
5667     flush_events();
5668     flush_sequence();
5669     SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5670     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
5671 
5672     flush_sequence();
5673     res = SendMessageA(hwnd, 0x3B, 0x8000000b, 0);
5674     if (!res)
5675     {
5676         todo_wine win_skip( "Message 0x3b not supported\n" );
5677         goto done;
5678     }
5679     ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE);
5680     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %ld\n", res);
5681     res = SendMessageA(hwnd, 0x3B, 0x0000000b, 0);
5682     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE);
5683     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %ld\n", res);
5684     res = SendMessageA(hwnd, 0x3B, 0x0000000f, 0);
5685     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE);
5686     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %ld\n", res);
5687 
5688     flush_sequence();
5689     res = SendMessageA(hwnd, 0x3B, 0x80000008, 0);
5690     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE);
5691     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %ld\n", res);
5692     res = SendMessageA(hwnd, 0x3B, 0x00000008, 0);
5693     ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE);
5694     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %ld\n", res);
5695 
5696     res = SendMessageA(hwnd, 0x3B, 0x80000004, 0);
5697     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE);
5698     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %ld\n", res);
5699 
5700     res = SendMessageA(hwnd, 0x3B, 0x80000001, 0);
5701     ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE);
5702     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %ld\n", res);
5703 
5704 done:
5705     DestroyWindow(hwnd);
5706     flush_sequence();
5707 }
5708 
5709 static void test_setwindowpos(void)
5710 {
5711     HWND hwnd;
5712     RECT rc;
5713     LRESULT res;
5714     const INT winX = 100;
5715     const INT winY = 100;
5716     const INT sysX = GetSystemMetrics(SM_CXMINTRACK);
5717 
5718     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
5719                            0, 0, winX, winY, 0,
5720                            NULL, NULL, 0);
5721 
5722     GetWindowRect(hwnd, &rc);
5723     expect(sysX, rc.right);
5724     expect(winY, rc.bottom);
5725 
5726     flush_events();
5727     flush_sequence();
5728     res = SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, winX, winY, 0);
5729     ok_sequence(WmZOrder, "Z-Order", TRUE);
5730     ok(res == TRUE, "SetWindowPos expected TRUE, got %ld\n", res);
5731 
5732     GetWindowRect(hwnd, &rc);
5733     expect(sysX, rc.right);
5734     expect(winY, rc.bottom);
5735     DestroyWindow(hwnd);
5736 }
5737 
5738 static void invisible_parent_tests(void)
5739 {
5740     HWND hparent, hchild;
5741 
5742     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
5743                               100, 100, 200, 200, 0, 0, 0, NULL);
5744     ok (hparent != 0, "Failed to create parent window\n");
5745     flush_sequence();
5746 
5747     /* test showing child with hidden parent */
5748 
5749     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5750                              0, 0, 10, 10, hparent, 0, 0, NULL);
5751     ok (hchild != 0, "Failed to create child window\n");
5752     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
5753 
5754     ShowWindow( hchild, SW_MINIMIZE );
5755     ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
5756     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5757     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5758 
5759     /* repeat */
5760     flush_events();
5761     flush_sequence();
5762     ShowWindow( hchild, SW_MINIMIZE );
5763     ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
5764 
5765     DestroyWindow(hchild);
5766     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5767                              0, 0, 10, 10, hparent, 0, 0, NULL);
5768     flush_sequence();
5769 
5770     ShowWindow( hchild, SW_MAXIMIZE );
5771     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
5772     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5773     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5774 
5775     /* repeat */
5776     flush_events();
5777     flush_sequence();
5778     ShowWindow( hchild, SW_MAXIMIZE );
5779     ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
5780 
5781     DestroyWindow(hchild);
5782     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5783                              0, 0, 10, 10, hparent, 0, 0, NULL);
5784     flush_sequence();
5785 
5786     ShowWindow( hchild, SW_RESTORE );
5787     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
5788     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5789     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5790 
5791     DestroyWindow(hchild);
5792     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5793                              0, 0, 10, 10, hparent, 0, 0, NULL);
5794     flush_sequence();
5795 
5796     ShowWindow( hchild, SW_SHOWMINIMIZED );
5797     ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
5798     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5799     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5800 
5801     /* repeat */
5802     flush_events();
5803     flush_sequence();
5804     ShowWindow( hchild, SW_SHOWMINIMIZED );
5805     ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
5806 
5807     DestroyWindow(hchild);
5808     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5809                              0, 0, 10, 10, hparent, 0, 0, NULL);
5810     flush_sequence();
5811 
5812     /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
5813     ShowWindow( hchild, SW_SHOWMAXIMIZED );
5814     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
5815     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5816     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5817 
5818     DestroyWindow(hchild);
5819     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5820                              0, 0, 10, 10, hparent, 0, 0, NULL);
5821     flush_sequence();
5822 
5823     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5824     ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5825     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5826     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5827 
5828     /* repeat */
5829     flush_events();
5830     flush_sequence();
5831     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5832     ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5833 
5834     DestroyWindow(hchild);
5835     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5836                              0, 0, 10, 10, hparent, 0, 0, NULL);
5837     flush_sequence();
5838 
5839     /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
5840     ShowWindow( hchild, SW_FORCEMINIMIZE );
5841     ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
5842 todo_wine {
5843     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5844 }
5845     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5846 
5847     DestroyWindow(hchild);
5848     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5849                              0, 0, 10, 10, hparent, 0, 0, NULL);
5850     flush_sequence();
5851 
5852     ShowWindow( hchild, SW_SHOWNA );
5853     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5854     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5855     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5856 
5857     /* repeat */
5858     flush_events();
5859     flush_sequence();
5860     ShowWindow( hchild, SW_SHOWNA );
5861     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5862 
5863     DestroyWindow(hchild);
5864     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5865                              0, 0, 10, 10, hparent, 0, 0, NULL);
5866     flush_sequence();
5867 
5868     ShowWindow( hchild, SW_SHOW );
5869     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5870     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5871     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5872 
5873     /* repeat */
5874     flush_events();
5875     flush_sequence();
5876     ShowWindow( hchild, SW_SHOW );
5877     ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5878 
5879     ShowWindow( hchild, SW_HIDE );
5880     ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
5881     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5882     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5883 
5884     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5885     ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
5886     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5887     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5888 
5889     SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5890     ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
5891     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
5892     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5893 
5894     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5895     flush_sequence();
5896     DestroyWindow(hchild);
5897     ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
5898 
5899     DestroyWindow(hparent);
5900     flush_sequence();
5901 }
5902 
5903 /****************** button message test *************************/
5904 #define ID_BUTTON 0x000e
5905 
5906 static const struct message WmSetFocusButtonSeq[] =
5907 {
5908     { HCBT_SETFOCUS, hook },
5909     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5910     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5911     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5912     { WM_SETFOCUS, sent|wparam, 0 },
5913     { WM_CTLCOLORBTN, sent|parent },
5914     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5915     { WM_APP, sent|wparam|lparam, 0, 0 },
5916     { 0 }
5917 };
5918 static const struct message WmKillFocusButtonSeq[] =
5919 {
5920     { HCBT_SETFOCUS, hook },
5921     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5922     { WM_KILLFOCUS, sent|wparam, 0 },
5923     { WM_CTLCOLORBTN, sent|parent },
5924     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5925     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5926     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5927     { WM_APP, sent|wparam|lparam, 0, 0 },
5928     { WM_PAINT, sent },
5929     { WM_CTLCOLORBTN, sent|parent },
5930     { 0 }
5931 };
5932 static const struct message WmSetFocusStaticSeq[] =
5933 {
5934     { HCBT_SETFOCUS, hook },
5935     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5936     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5937     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5938     { WM_SETFOCUS, sent|wparam, 0 },
5939     { WM_CTLCOLORSTATIC, sent|parent },
5940     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5941     { WM_COMMAND, sent|wparam|parent|optional, MAKEWPARAM(ID_BUTTON, BN_CLICKED) }, /* radio button */
5942     { WM_APP, sent|wparam|lparam, 0, 0 },
5943     { 0 }
5944 };
5945 static const struct message WmKillFocusStaticSeq[] =
5946 {
5947     { HCBT_SETFOCUS, hook },
5948     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5949     { WM_KILLFOCUS, sent|wparam, 0 },
5950     { WM_CTLCOLORSTATIC, sent|parent },
5951     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5952     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5953     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5954     { WM_APP, sent|wparam|lparam, 0, 0 },
5955     { WM_PAINT, sent },
5956     { WM_CTLCOLORSTATIC, sent|parent },
5957     { 0 }
5958 };
5959 static const struct message WmSetFocusOwnerdrawSeq[] =
5960 {
5961     { HCBT_SETFOCUS, hook },
5962     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5963     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5964     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5965     { WM_SETFOCUS, sent|wparam, 0 },
5966     { WM_CTLCOLORBTN, sent|parent },
5967     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x001040e4 },
5968     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5969     { WM_APP, sent|wparam|lparam, 0, 0 },
5970     { 0 }
5971 };
5972 static const struct message WmKillFocusOwnerdrawSeq[] =
5973 {
5974     { HCBT_SETFOCUS, hook },
5975     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5976     { WM_KILLFOCUS, sent|wparam, 0 },
5977     { WM_CTLCOLORBTN, sent|parent },
5978     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000040e4 },
5979     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5980     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5981     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5982     { WM_APP, sent|wparam|lparam, 0, 0 },
5983     { WM_PAINT, sent },
5984     { WM_CTLCOLORBTN, sent|parent },
5985     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
5986     { 0 }
5987 };
5988 static const struct message WmLButtonDownSeq[] =
5989 {
5990     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
5991     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5992     { HCBT_SETFOCUS, hook },
5993     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
5994     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5995     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5996     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
5997     { WM_CTLCOLORBTN, sent|defwinproc },
5998     { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
5999     { WM_CTLCOLORBTN, sent|defwinproc },
6000     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6001     { 0 }
6002 };
6003 static const struct message WmLButtonDownStaticSeq[] =
6004 {
6005     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
6006     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6007     { HCBT_SETFOCUS, hook },
6008     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
6009     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
6010     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6011     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
6012     { WM_CTLCOLORSTATIC, sent|defwinproc },
6013     { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
6014     { WM_CTLCOLORSTATIC, sent|defwinproc },
6015     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6016     { 0 }
6017 };
6018 static const struct message WmLButtonUpSeq[] =
6019 {
6020     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6021     { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6022     { WM_CTLCOLORBTN, sent|defwinproc },
6023     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6024     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6025     { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6026     { 0 }
6027 };
6028 static const struct message WmLButtonUpStaticSeq[] =
6029 {
6030     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6031     { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6032     { WM_CTLCOLORSTATIC, sent|defwinproc },
6033     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6034     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6035     { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6036     { 0 }
6037 };
6038 static const struct message WmLButtonUpAutoSeq[] =
6039 {
6040     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6041     { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6042     { WM_CTLCOLORSTATIC, sent|defwinproc },
6043     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6044     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6045     { BM_SETCHECK, sent|defwinproc },
6046     { WM_CTLCOLORSTATIC, sent|defwinproc, 0, 0 },
6047     { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6048     { 0 }
6049 };
6050 static const struct message WmLButtonUpBrokenSeq[] =
6051 {
6052     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6053     { 0 }
6054 };
6055 static const struct message WmSetFontButtonSeq[] =
6056 {
6057     { WM_SETFONT, sent },
6058     { WM_PAINT, sent },
6059     { WM_ERASEBKGND, sent|defwinproc|optional },
6060     { WM_CTLCOLORBTN, sent|defwinproc },
6061     { WM_CTLCOLORBTN, sent|defwinproc|optional }, /* FIXME: Wine sends it twice for BS_OWNERDRAW */
6062     { 0 }
6063 };
6064 static const struct message WmSetFontStaticSeq[] =
6065 {
6066     { WM_SETFONT, sent },
6067     { WM_PAINT, sent },
6068     { WM_ERASEBKGND, sent|defwinproc|optional },
6069     { WM_CTLCOLORSTATIC, sent|defwinproc },
6070     { 0 }
6071 };
6072 static const struct message WmSetTextButtonSeq[] =
6073 {
6074     { WM_SETTEXT, sent },
6075     { WM_CTLCOLORBTN, sent|parent },
6076     { WM_CTLCOLORBTN, sent|parent },
6077     { WM_COMMAND, sent|parent|optional },
6078     { WM_DRAWITEM, sent|parent|optional },
6079     { 0 }
6080 };
6081 static const struct message WmSetTextStaticSeq[] =
6082 {
6083     { WM_SETTEXT, sent },
6084     { WM_CTLCOLORSTATIC, sent|parent },
6085     { WM_CTLCOLORSTATIC, sent|parent },
6086     { 0 }
6087 };
6088 static const struct message WmSetTextGroupSeq[] =
6089 {
6090     { WM_SETTEXT, sent },
6091     { WM_CTLCOLORSTATIC, sent|parent },
6092     { WM_CTLCOLORSTATIC, sent|parent|optional }, /* FIXME: Missing in Wine */
6093     { WM_CTLCOLORSTATIC, sent|parent|optional }, /* FIXME: Missing in Wine */
6094     { 0 }
6095 };
6096 static const struct message WmSetTextInvisibleSeq[] =
6097 {
6098     { WM_SETTEXT, sent },
6099     { 0 }
6100 };
6101 static const struct message WmSetStyleButtonSeq[] =
6102 {
6103     { BM_SETSTYLE, sent },
6104     { WM_APP, sent|wparam|lparam, 0, 0 },
6105     { WM_PAINT, sent },
6106     { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6107     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6108     { WM_CTLCOLORBTN, sent|parent },
6109     { 0 }
6110 };
6111 static const struct message WmSetStyleStaticSeq[] =
6112 {
6113     { BM_SETSTYLE, sent },
6114     { WM_APP, sent|wparam|lparam, 0, 0 },
6115     { WM_PAINT, sent },
6116     { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6117     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6118     { WM_CTLCOLORSTATIC, sent|parent },
6119     { 0 }
6120 };
6121 static const struct message WmSetStyleUserSeq[] =
6122 {
6123     { BM_SETSTYLE, sent },
6124     { WM_APP, sent|wparam|lparam, 0, 0 },
6125     { WM_PAINT, sent },
6126     { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6127     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6128     { WM_CTLCOLORBTN, sent|parent },
6129     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_PAINT) },
6130     { 0 }
6131 };
6132 static const struct message WmSetStyleOwnerdrawSeq[] =
6133 {
6134     { BM_SETSTYLE, sent },
6135     { WM_APP, sent|wparam|lparam, 0, 0 },
6136     { WM_PAINT, sent },
6137     { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
6138     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6139     { WM_CTLCOLORBTN, sent|parent },
6140     { WM_CTLCOLORBTN, sent|parent|optional }, /* Win9x doesn't send it */
6141     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
6142     { 0 }
6143 };
6144 static const struct message WmSetStateButtonSeq[] =
6145 {
6146     { BM_SETSTATE, sent },
6147     { WM_CTLCOLORBTN, sent|parent },
6148     { WM_APP, sent|wparam|lparam, 0, 0 },
6149     { 0 }
6150 };
6151 static const struct message WmSetStateStaticSeq[] =
6152 {
6153     { BM_SETSTATE, sent },
6154     { WM_CTLCOLORSTATIC, sent|parent },
6155     { WM_APP, sent|wparam|lparam, 0, 0 },
6156     { 0 }
6157 };
6158 static const struct message WmSetStateUserSeq[] =
6159 {
6160     { BM_SETSTATE, sent },
6161     { WM_CTLCOLORBTN, sent|parent },
6162     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_HILITE) },
6163     { WM_APP, sent|wparam|lparam, 0, 0 },
6164     { 0 }
6165 };
6166 static const struct message WmSetStateOwnerdrawSeq[] =
6167 {
6168     { BM_SETSTATE, sent },
6169     { WM_CTLCOLORBTN, sent|parent },
6170     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000120e4 },
6171     { WM_APP, sent|wparam|lparam, 0, 0 },
6172     { 0 }
6173 };
6174 static const struct message WmClearStateButtonSeq[] =
6175 {
6176     { BM_SETSTATE, sent },
6177     { WM_CTLCOLORBTN, sent|parent },
6178     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_UNHILITE) },
6179     { WM_APP, sent|wparam|lparam, 0, 0 },
6180     { 0 }
6181 };
6182 static const struct message WmDisableButtonSeq[] =
6183 {
6184     { WM_LBUTTONDOWN, sent },
6185     { BM_SETSTATE, sent|defwinproc },
6186     { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6187     { WM_CTLCOLORBTN, sent|optional },
6188     { WM_LBUTTONUP, sent },
6189     { BM_SETSTATE, sent|defwinproc },
6190     { WM_CTLCOLORBTN, sent|defwinproc|optional },
6191     { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6192     { BM_SETCHECK, sent|defwinproc|optional },
6193     { WM_CTLCOLORBTN, sent|optional },
6194     { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6195     { WM_CAPTURECHANGED, sent|defwinproc },
6196     { WM_COMMAND, sent },
6197     { 0 }
6198 };
6199 static const struct message WmClearStateOwnerdrawSeq[] =
6200 {
6201     { BM_SETSTATE, sent },
6202     { WM_CTLCOLORBTN, sent|parent },
6203     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000020e4 },
6204     { WM_APP, sent|wparam|lparam, 0, 0 },
6205     { 0 }
6206 };
6207 static const struct message WmSetCheckIgnoredSeq[] =
6208 {
6209     { BM_SETCHECK, sent },
6210     { WM_APP, sent|wparam|lparam, 0, 0 },
6211     { 0 }
6212 };
6213 static const struct message WmSetCheckStaticSeq[] =
6214 {
6215     { BM_SETCHECK, sent },
6216     { WM_CTLCOLORSTATIC, sent|parent },
6217     { WM_APP, sent|wparam|lparam, 0, 0 },
6218     { 0 }
6219 };
6220 
6221 static WNDPROC old_button_proc;
6222 
6223 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6224 {
6225     static LONG defwndproc_counter = 0;
6226     LRESULT ret;
6227     struct recvd_message msg;
6228 
6229     if (ignore_message( message )) return 0;
6230 
6231     switch (message)
6232     {
6233     case WM_SYNCPAINT:
6234         break;
6235     case BM_SETSTATE:
6236         if (GetCapture())
6237             ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
6238 
6239         lParam = (ULONG_PTR)GetMenu(hwnd);
6240         goto log_it;
6241 
6242     case WM_GETDLGCODE:
6243         if (lParam)
6244         {
6245             MSG *msg = (MSG *)lParam;
6246             lParam = MAKELPARAM(msg->message, msg->wParam);
6247         }
6248         wParam = (ULONG_PTR)GetMenu(hwnd);
6249         goto log_it;
6250 
6251     case BM_SETCHECK:
6252     case BM_GETCHECK:
6253         lParam = (ULONG_PTR)GetMenu(hwnd);
6254         /* fall through */
6255 log_it:
6256     default:
6257         msg.hwnd = hwnd;
6258         msg.message = message;
6259         msg.flags = sent|wparam|lparam;
6260         if (defwndproc_counter) msg.flags |= defwinproc;
6261         msg.wParam = wParam;
6262         msg.lParam = lParam;
6263         msg.descr = "button";
6264         add_message(&msg);
6265     }
6266 
6267     defwndproc_counter++;
6268     ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
6269     defwndproc_counter--;
6270 
6271     return ret;
6272 }
6273 
6274 static void subclass_button(void)
6275 {
6276     WNDCLASSA cls;
6277 
6278     if (!GetClassInfoA(0, "button", &cls)) assert(0);
6279 
6280     old_button_proc = cls.lpfnWndProc;
6281 
6282     cls.hInstance = GetModuleHandleA(NULL);
6283     cls.lpfnWndProc = button_hook_proc;
6284     cls.lpszClassName = "my_button_class";
6285     UnregisterClassA(cls.lpszClassName, cls.hInstance);
6286     if (!RegisterClassA(&cls)) assert(0);
6287 }
6288 
6289 static void test_button_messages(void)
6290 {
6291     static const struct
6292     {
6293         DWORD style;
6294         DWORD dlg_code;
6295         const struct message *setfocus;
6296         const struct message *killfocus;
6297         const struct message *setstyle;
6298         const struct message *setstate;
6299         const struct message *clearstate;
6300         const struct message *setcheck;
6301         const struct message *lbuttondown;
6302         const struct message *lbuttonup;
6303         const struct message *setfont;
6304         const struct message *settext;
6305     } button[] = {
6306         { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
6307           WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
6308           WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq,
6309           WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6310           WmSetTextButtonSeq },
6311         { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
6312           WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
6313           WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq,
6314           WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6315           WmSetTextButtonSeq },
6316         { BS_CHECKBOX, DLGC_BUTTON,
6317           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6318           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6319           WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6320           WmSetTextStaticSeq },
6321         { BS_AUTOCHECKBOX, DLGC_BUTTON,
6322           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6323           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6324           WmLButtonDownStaticSeq, WmLButtonUpAutoSeq, WmSetFontStaticSeq,
6325           WmSetTextStaticSeq },
6326         { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
6327           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6328           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6329           WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6330           WmSetTextStaticSeq },
6331         { BS_3STATE, DLGC_BUTTON,
6332           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6333           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6334           WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6335           WmSetTextStaticSeq },
6336         { BS_AUTO3STATE, DLGC_BUTTON,
6337           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6338           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6339           WmLButtonDownStaticSeq, WmLButtonUpAutoSeq, WmSetFontStaticSeq,
6340           WmSetTextStaticSeq },
6341         { BS_GROUPBOX, DLGC_STATIC,
6342           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6343           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckIgnoredSeq,
6344           WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6345           WmSetTextGroupSeq },
6346         { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
6347           WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleUserSeq,
6348           WmSetStateUserSeq, WmClearStateButtonSeq, WmSetCheckIgnoredSeq,
6349           WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6350           WmSetTextButtonSeq },
6351         { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
6352           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6353           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6354           NULL /* avoid infinite loop */, WmLButtonUpBrokenSeq, WmSetFontStaticSeq,
6355           WmSetTextStaticSeq },
6356         { BS_OWNERDRAW, DLGC_BUTTON,
6357           WmSetFocusOwnerdrawSeq, WmKillFocusOwnerdrawSeq, WmSetStyleOwnerdrawSeq,
6358           WmSetStateOwnerdrawSeq, WmClearStateOwnerdrawSeq, WmSetCheckIgnoredSeq,
6359           WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6360           WmSetTextButtonSeq },
6361     };
6362     LOGFONTA logfont = { 0 };
6363     HFONT zfont, hfont2;
6364     unsigned int i;
6365     HWND hwnd, parent;
6366     DWORD dlg_code;
6367 
6368     /* selection with VK_SPACE should capture button window */
6369     hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP,
6370                            0, 0, 50, 14, 0, 0, 0, NULL);
6371     ok(hwnd != 0, "Failed to create button window\n");
6372     ReleaseCapture();
6373     SetFocus(hwnd);
6374     SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
6375     ok(GetCapture() == hwnd, "Should be captured on VK_SPACE WM_KEYDOWN\n");
6376     SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
6377     DestroyWindow(hwnd);
6378 
6379     subclass_button();
6380 
6381     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6382                              100, 100, 200, 200, 0, 0, 0, NULL);
6383     ok(parent != 0, "Failed to create parent window\n");
6384 
6385     memset(&logfont, 0, sizeof(logfont));
6386     logfont.lfHeight = -12;
6387     logfont.lfWeight = FW_NORMAL;
6388     strcpy(logfont.lfFaceName, "Tahoma");
6389 
6390     hfont2 = CreateFontIndirectA(&logfont);
6391     ok(hfont2 != NULL, "Failed to create Tahoma font\n");
6392 
6393     for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
6394     {
6395         MSG msg;
6396         DWORD style, state;
6397         HFONT prevfont;
6398         char desc[64];
6399         HDC hdc;
6400 
6401         trace("button style %08x\n", button[i].style);
6402 
6403         hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_CHILD | BS_NOTIFY,
6404                                0, 0, 50, 14, parent, (HMENU)ID_BUTTON, 0, NULL);
6405         ok(hwnd != 0, "Failed to create button window\n");
6406 
6407         style = GetWindowLongA(hwnd, GWL_STYLE);
6408         style &= ~(WS_CHILD | BS_NOTIFY);
6409         /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
6410         if (button[i].style == BS_USERBUTTON)
6411             ok(style == BS_PUSHBUTTON, "expected style BS_PUSHBUTTON got %x\n", style);
6412         else
6413             ok(style == button[i].style, "expected style %x got %x\n", button[i].style, style);
6414 
6415         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
6416         ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
6417 
6418         ShowWindow(hwnd, SW_SHOW);
6419         UpdateWindow(hwnd);
6420         SetFocus(0);
6421         flush_events();
6422         SetFocus(0);
6423         flush_sequence();
6424 
6425         log_all_parent_messages++;
6426 
6427         ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
6428         SetFocus(hwnd);
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].setfocus, "SetFocus(hwnd) on a button", FALSE);
6432 
6433         SetFocus(0);
6434         SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6435         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6436         ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
6437 
6438         ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
6439 
6440         SendMessageA(hwnd, BM_SETSTYLE, button[i].style | BS_BOTTOM, TRUE);
6441         SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6442         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6443         ok_sequence(button[i].setstyle, "BM_SETSTYLE on a button", FALSE);
6444 
6445         style = GetWindowLongA(hwnd, GWL_STYLE);
6446         style &= ~(WS_VISIBLE | WS_CHILD | BS_NOTIFY);
6447         /* XP doesn't turn a BS_USERBUTTON into BS_PUSHBUTTON here! */
6448         ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6449 
6450         state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6451         ok(state == 0, "expected state 0, got %04x\n", state);
6452 
6453         flush_sequence();
6454 
6455         SendMessageA(hwnd, BM_SETSTATE, TRUE, 0);
6456         SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6457         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6458         ok_sequence(button[i].setstate, "BM_SETSTATE/TRUE on a button", FALSE);
6459 
6460         state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6461         ok(state == 0x0004, "expected state 0x0004, got %04x\n", state);
6462 
6463         style = GetWindowLongA(hwnd, GWL_STYLE);
6464         style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6465         ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6466 
6467         flush_sequence();
6468 
6469         SendMessageA(hwnd, BM_SETSTATE, FALSE, 0);
6470         SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6471         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6472         ok_sequence(button[i].clearstate, "BM_SETSTATE/FALSE on a button", FALSE);
6473 
6474         state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6475         ok(state == 0, "expected state 0, got %04x\n", state);
6476 
6477         style = GetWindowLongA(hwnd, GWL_STYLE);
6478         style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6479         ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6480 
6481         state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6482         ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
6483 
6484         flush_sequence();
6485 
6486         SendMessageA(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
6487         SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6488         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6489         ok_sequence(WmSetCheckIgnoredSeq, "BM_SETCHECK on a button", FALSE);
6490 
6491         state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6492         ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
6493 
6494         style = GetWindowLongA(hwnd, GWL_STYLE);
6495         style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6496         ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6497 
6498         flush_sequence();
6499 
6500         SendMessageA(hwnd, BM_SETCHECK, BST_CHECKED, 0);
6501         SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6502         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6503         ok_sequence(button[i].setcheck, "BM_SETCHECK on a button", FALSE);
6504 
6505         SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 1");
6506         sprintf(desc, "button[%i]: WM_SETTEXT on a visible button", i);
6507         ok_sequence(button[i].settext, desc, FALSE);
6508 
6509         ShowWindow(hwnd, SW_HIDE);
6510         flush_events();
6511         flush_sequence();
6512 
6513         SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 2");
6514         sprintf(desc, "button[%i]: WM_SETTEXT on an invisible button", i);
6515         ok_sequence(WmSetTextInvisibleSeq, desc, FALSE);
6516 
6517         ShowWindow(hwnd, SW_SHOW);
6518         ShowWindow(parent, SW_HIDE);
6519         flush_events();
6520         flush_sequence();
6521 
6522         SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 3");
6523         sprintf(desc, "button[%i]: WM_SETTEXT on an invisible button", i);
6524         ok_sequence(WmSetTextInvisibleSeq, desc, FALSE);
6525 
6526         ShowWindow(parent, SW_SHOW);
6527         flush_events();
6528 
6529         state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6530         if (button[i].style == BS_PUSHBUTTON ||
6531             button[i].style == BS_DEFPUSHBUTTON ||
6532             button[i].style == BS_GROUPBOX ||
6533             button[i].style == BS_USERBUTTON ||
6534             button[i].style == BS_OWNERDRAW)
6535             ok(state == BST_UNCHECKED, "expected check 0, got %04x\n", state);
6536         else
6537             ok(state == BST_CHECKED, "expected check 1, got %04x\n", state);
6538 
6539         style = GetWindowLongA(hwnd, GWL_STYLE);
6540         style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6541         if (button[i].style == BS_RADIOBUTTON ||
6542             button[i].style == BS_AUTORADIOBUTTON)
6543             ok(style == (button[i].style | WS_TABSTOP), "expected style %04x | WS_TABSTOP got %04x\n", button[i].style, style);
6544         else
6545             ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6546 
6547         log_all_parent_messages--;
6548 
6549         DestroyWindow(hwnd);
6550 
6551         hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP | WS_VISIBLE,
6552                                0, 0, 50, 14, 0, 0, 0, NULL);
6553         ok(hwnd != 0, "Failed to create button window\n");
6554 
6555         SetForegroundWindow(hwnd);
6556         flush_events();
6557 
6558         SetActiveWindow(hwnd);
6559         SetFocus(0);
6560         flush_sequence();
6561 
6562         if (button[i].lbuttondown)
6563         {
6564             SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
6565             sprintf(desc, "button[%i]: WM_LBUTTONDOWN on a button", i);
6566             ok_sequence(button[i].lbuttondown, desc, FALSE);
6567         }
6568 
6569         SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
6570         sprintf(desc, "button[%i]: WM_LBUTTONUP on a button", i);
6571         ok_sequence(button[i].lbuttonup, desc, FALSE);
6572 
6573         flush_sequence();
6574         zfont = GetStockObject(DEFAULT_GUI_FONT);
6575         SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
6576         UpdateWindow(hwnd);
6577         sprintf(desc, "button[%i]: WM_SETFONT on a button", i);
6578         ok_sequence(button[i].setfont, desc, FALSE);
6579 
6580         /* Test that original font is not selected back after painting */
6581         hdc = CreateCompatibleDC(0);
6582 
6583         prevfont = SelectObject(hdc, hfont2);
6584         ok(prevfont == GetStockObject(SYSTEM_FONT), "Unexpected default font\n");
6585         SendMessageA(hwnd, WM_PRINTCLIENT, (WPARAM)hdc, 0);
6586         ok(hfont2 != GetCurrentObject(hdc, OBJ_FONT), "button[%u]: unexpected font selected after WM_PRINTCLIENT\n", i);
6587         SelectObject(hdc, prevfont);
6588 
6589         prevfont = SelectObject(hdc, hfont2);
6590         ok(prevfont == GetStockObject(SYSTEM_FONT), "Unexpected default font\n");
6591         SendMessageA(hwnd, WM_PAINT, (WPARAM)hdc, 0);
6592         ok(hfont2 != GetCurrentObject(hdc, OBJ_FONT), "button[%u]: unexpected font selected after WM_PAINT\n", i);
6593         SelectObject(hdc, prevfont);
6594 
6595         DeleteDC(hdc);
6596 
6597         DestroyWindow(hwnd);
6598     }
6599 
6600     DeleteObject(hfont2);
6601     DestroyWindow(parent);
6602 
6603     /* Test if WM_LBUTTONDOWN and WM_LBUTTONUP to a disabled button leads to a WM_COMMAND for the parent */
6604 
6605     parent = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6606             100, 100, 200, 200, 0, 0, 0, NULL);
6607     ok (hwnd != 0, "Failed to create overlapped window\n");
6608 
6609     hwnd = CreateWindowExA(0, "my_button_class", "test", BS_DEFPUSHBUTTON | WS_VISIBLE | WS_CHILD,
6610                                    0, 0, 50, 14, parent, 0, 0, NULL);
6611 
6612     EnableWindow(hwnd, FALSE);
6613     flush_sequence();
6614     SendMessageA(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, 0);
6615     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
6616     ok_sequence(WmDisableButtonSeq, "Mouseclick on a disabled button", FALSE);
6617 
6618     DestroyWindow(hwnd);
6619     DestroyWindow(parent);
6620 }
6621 
6622 #define ID_RADIO1 501
6623 #define ID_RADIO2 502
6624 #define ID_RADIO3 503
6625 #define ID_TEXT   504
6626 
6627 static const struct message auto_radio_button_BM_CLICK[] =
6628 {
6629     { BM_CLICK, sent|wparam|lparam, 0, 0 },
6630     { WM_LBUTTONDOWN, sent|wparam|lparam|defwinproc, 0, 0 },
6631     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6632     { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO2 },
6633     { WM_CTLCOLORSTATIC, sent|parent },
6634     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6635     { WM_LBUTTONUP, sent|wparam|lparam|defwinproc, 0, 0 },
6636     { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO2 },
6637     { WM_CTLCOLORSTATIC, sent|parent },
6638     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6639     { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO2, 0 },
6640     { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO2 },
6641     { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO1, 0 },
6642     { BM_SETCHECK, sent|wparam|lparam|defwinproc, 0, ID_RADIO1 },
6643     { WM_CTLCOLORSTATIC, sent|parent },
6644     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6645     { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO3, 0 },
6646     { BM_SETCHECK, sent|wparam|lparam|defwinproc, 0, ID_RADIO3 },
6647     { WM_CTLCOLORSTATIC, sent|parent },
6648     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6649     { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_TEXT, 0 },
6650     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6651     { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
6652     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO2, BN_CLICKED) },
6653     { WM_NCHITTEST, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6654     { WM_SETCURSOR, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6655     { WM_MOUSEMOVE, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6656     { 0 }
6657 };
6658 
6659 static const struct message auto_radio_button_VK_UP_child[] =
6660 {
6661     { WM_KEYDOWN, sent|wparam|lparam, VK_UP, 0 },
6662     { WM_KEYUP, sent|wparam|lparam, VK_UP, 0 },
6663     { 0 }
6664 };
6665 
6666 static const struct message auto_radio_button_VK_UP_parent[] =
6667 {
6668     { WM_KEYDOWN, sent|wparam|lparam|parent, VK_UP, 0 },
6669     { WM_KEYUP, sent|wparam|lparam|parent, VK_UP, 0 },
6670     { 0 }
6671 };
6672 
6673 static const struct message auto_radio_button_VK_UP_dialog[] =
6674 {
6675     { WM_GETDLGCODE, sent|parent, 0, 0 },
6676 
6677     /* optional trailer seen on some windows setups */
6678     { WM_CHANGEUISTATE, sent|optional },
6679     { WM_UPDATEUISTATE, sent|optional },
6680     { WM_UPDATEUISTATE, sent|optional },
6681     { WM_UPDATEUISTATE, sent|optional },
6682     { WM_UPDATEUISTATE, sent|optional },
6683     { WM_UPDATEUISTATE, sent|optional },
6684     { WM_UPDATEUISTATE, sent|optional },
6685     { WM_UPDATEUISTATE, sent|optional },
6686     { WM_UPDATEUISTATE, sent|optional },
6687     { WM_UPDATEUISTATE, sent|optional },
6688     { WM_UPDATEUISTATE, sent|optional },
6689     { WM_UPDATEUISTATE, sent|optional },
6690     { WM_UPDATEUISTATE, sent|optional },
6691     { WM_UPDATEUISTATE, sent|optional },
6692     { WM_UPDATEUISTATE, sent|optional },
6693     { WM_UPDATEUISTATE, sent|optional },
6694     { WM_UPDATEUISTATE, sent|optional },
6695     { WM_UPDATEUISTATE, sent|optional },
6696     { WM_UPDATEUISTATE, sent|optional },
6697     { WM_CTLCOLORSTATIC, sent|parent|optional },
6698     { WM_CTLCOLORSTATIC, sent|parent|optional },
6699     { WM_CTLCOLORSTATIC, sent|parent|optional },
6700     { WM_UPDATEUISTATE, sent|optional },
6701     { WM_CTLCOLORSTATIC, sent|parent|optional },
6702     { WM_CTLCOLORSTATIC, sent|parent|optional },
6703     { WM_UPDATEUISTATE, sent|optional },
6704     { WM_CTLCOLORBTN, sent|parent|optional },
6705     { WM_CTLCOLORBTN, sent|parent|optional },
6706     { WM_UPDATEUISTATE, sent|optional },
6707     { WM_CTLCOLORSTATIC, sent|parent|optional },
6708     { WM_CTLCOLORSTATIC, sent|parent|optional },
6709     { 0 }
6710 };
6711 
6712 static const struct message auto_radio_button_VK_DOWN_dialog[] =
6713 {
6714     { WM_GETDLGCODE, sent|parent, 0, 0 },
6715     { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, MAKELPARAM(WM_KEYDOWN, VK_DOWN) },
6716     { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
6717     { HCBT_SETFOCUS, hook },
6718     { WM_KILLFOCUS, sent, 0, 0 },
6719     { WM_CTLCOLORSTATIC, sent|parent },
6720     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO3, BN_KILLFOCUS) },
6721     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6722     { WM_SETFOCUS, sent, 0, 0 },
6723     { WM_CTLCOLORSTATIC, sent|parent },
6724     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_SETFOCUS) },
6725     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_CLICKED) },
6726     { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
6727     { WM_GETDLGCODE, sent|parent, 0, 0 },
6728     { DM_GETDEFID, sent|parent, 0, 0 },
6729     { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
6730     { BM_CLICK, sent|wparam|lparam, 1, 0 },
6731     { WM_LBUTTONDOWN, sent|wparam|lparam|defwinproc, 0, 0 },
6732     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6733     { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO1 },
6734     { WM_CTLCOLORSTATIC, sent|parent },
6735     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6736     { WM_LBUTTONUP, sent|wparam|lparam|defwinproc, 0, 0 },
6737     { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO1 },
6738     { WM_CTLCOLORSTATIC, sent|parent },
6739     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6740     { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO1, 0 },
6741     { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO1 },
6742     { WM_CTLCOLORSTATIC, sent|parent },
6743     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6744     { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO3, 0 },
6745     { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO3 },
6746     { WM_CTLCOLORSTATIC, sent|parent },
6747     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6748     { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_TEXT, 0 },
6749     { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO2, 0 },
6750     { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO2 },
6751     { WM_CTLCOLORSTATIC, sent|parent },
6752     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 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_RADIO1, 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     { WM_PAINT, sent },
6760     { WM_CTLCOLORSTATIC, sent|parent },
6761     { 0 }
6762 };
6763 
6764 static const struct message auto_radio_button_VK_DOWN_radio3[] =
6765 {
6766     { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
6767     { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO2 },
6768     { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO3 },
6769     { WM_GETDLGCODE, sent|parent, 0, 0 },
6770     { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, MAKELPARAM(WM_KEYDOWN, VK_DOWN) },
6771     { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
6772     { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
6773     { WM_GETDLGCODE, sent|wparam|lparam|parent, 0, 0 },
6774     { WM_USER, sent|parent, 0, 0 },
6775     { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
6776     { 0 }
6777 };
6778 
6779 static const struct message auto_radio_button_VK_UP_radio1[] =
6780 {
6781     { WM_GETDLGCODE, sent|parent, 0, 0 },
6782     { 0 }
6783 };
6784 
6785 static INT_PTR WINAPI radio_test_dlg_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
6786 {
6787     ParentMsgCheckProcA(hwnd, msg, wp, lp);
6788     return 1;
6789 }
6790 
6791 static void test_autoradio_BM_CLICK(void)
6792 {
6793     HWND parent, radio1, radio2, radio3;
6794     RECT rc;
6795     MSG msg;
6796     DWORD ret;
6797 
6798     subclass_button();
6799 
6800     parent = CreateDialogParamA(0, "AUTORADIO_TEST_DIALOG_1", 0, radio_test_dlg_proc, 0);
6801     ok(parent != 0, "failed to create parent window\n");
6802 
6803     radio1 = GetDlgItem(parent, ID_RADIO1);
6804     radio2 = GetDlgItem(parent, ID_RADIO2);
6805     radio3 = GetDlgItem(parent, ID_RADIO3);
6806 
6807     /* this avoids focus messages in the generated sequence */
6808     SetFocus(radio2);
6809 
6810     flush_events();
6811     flush_sequence();
6812 
6813     ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6814     ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6815     ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6816     ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6817     ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6818     ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6819 
6820     SendMessageA(radio1, BM_SETCHECK, BST_CHECKED, 0);
6821 
6822     ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6823     ok(ret == BST_CHECKED, "got %08x\n", ret);
6824     ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6825     ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6826     ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6827     ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6828 
6829     SendMessageA(radio2, BM_SETCHECK, BST_CHECKED, 0);
6830 
6831     ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6832     ok(ret == BST_CHECKED, "got %08x\n", ret);
6833     ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6834     ok(ret == BST_CHECKED, "got %08x\n", ret);
6835     ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6836     ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6837 
6838     SendMessageA(radio3, BM_SETCHECK, BST_CHECKED, 0);
6839 
6840     ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6841     ok(ret == BST_CHECKED, "got %08x\n", ret);
6842     ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6843     ok(ret == BST_CHECKED, "got %08x\n", ret);
6844     ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6845     ok(ret == BST_CHECKED, "got %08x\n", ret);
6846 
6847     GetWindowRect(radio2, &rc);
6848     SetCursorPos(rc.left+1, rc.top+1);
6849 
6850     flush_events();
6851     flush_sequence();
6852 
6853     log_all_parent_messages++;
6854 
6855     SendMessageA(radio2, BM_CLICK, 0, 0);
6856     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6857     ok_sequence(auto_radio_button_BM_CLICK, "BM_CLICK on auto-radio button", FALSE);
6858 
6859     log_all_parent_messages--;
6860 
6861     ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6862     ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6863     ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6864     ok(ret == BST_CHECKED, "got %08x\n", ret);
6865     ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6866     ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6867 
6868     DestroyWindow(parent);
6869 }
6870 
6871 #define test_radio(r1, s1, r2, s2, r3, s3) test_radio_dbg(r1, s1, r2, s2, r3, s3, __LINE__)
6872 static void test_radio_dbg(HWND radio1, int state1, HWND radio2, int state2, HWND radio3, int state3, int line)
6873 {
6874     DWORD ret;
6875 
6876     ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6877     ok_(__FILE__,line)(ret == state1 ? BST_CHECKED : BST_UNCHECKED, "got %08x\n", ret);
6878     ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6879     ok_(__FILE__,line)(ret == state2 ? BST_CHECKED : BST_UNCHECKED, "got %08x\n", ret);
6880     ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6881     ok_(__FILE__,line)(ret == state3 ? BST_CHECKED : BST_UNCHECKED, "got %08x\n", ret);
6882 }
6883 
6884 static void set_radio(HWND radio1, int state1, HWND radio2, int state2, HWND radio3, int state3)
6885 {
6886     SendMessageA(radio1, BM_SETCHECK, state1 ? BST_CHECKED : BST_UNCHECKED, 0);
6887     SendMessageA(radio2, BM_SETCHECK, state2 ? BST_CHECKED : BST_UNCHECKED, 0);
6888     SendMessageA(radio3, BM_SETCHECK, state3 ? BST_CHECKED : BST_UNCHECKED, 0);
6889 }
6890 
6891 static void test_autoradio_kbd_move(void)
6892 {
6893     HWND parent, radio1, radio2, radio3, hwnd;
6894     RECT rc;
6895     MSG msg;
6896     DWORD ret;
6897 
6898     subclass_button();
6899 
6900     parent = CreateDialogParamA(0, "AUTORADIO_TEST_DIALOG_2", 0, radio_test_dlg_proc, 0);
6901     ok(parent != 0, "failed to create parent window\n");
6902 
6903     radio1 = GetDlgItem(parent, ID_RADIO1);
6904     radio2 = GetDlgItem(parent, ID_RADIO2);
6905     radio3 = GetDlgItem(parent, ID_RADIO3);
6906 
6907     flush_events();
6908     flush_sequence();
6909 
6910     test_radio(radio1, 0, radio2, 0, radio3, 0);
6911     set_radio(radio1, 1, radio2, 1, radio3, 1);
6912     test_radio(radio1, 1, radio2, 1, radio3, 1);
6913 
6914     SetFocus(radio3);
6915 
6916     flush_events();
6917     flush_sequence();
6918 
6919     log_all_parent_messages++;
6920 
6921     SendMessageA(radio3, WM_KEYDOWN, VK_UP, 0);
6922     SendMessageA(radio3, WM_KEYUP, VK_UP, 0);
6923     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6924     ok_sequence(auto_radio_button_VK_UP_child, "press/release VK_UP on auto-radio button", FALSE);
6925 
6926     test_radio(radio1, 1, radio2, 1, radio3, 1);
6927 
6928     flush_events();
6929     flush_sequence();
6930 
6931     DefDlgProcA(parent, WM_KEYDOWN, VK_UP, 0);
6932     DefDlgProcA(parent, WM_KEYUP, VK_UP, 0);
6933     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6934     ok_sequence(auto_radio_button_VK_UP_parent, "press/release VK_UP on dialog", FALSE);
6935 
6936     test_radio(radio1, 1, radio2, 1, radio3, 1);
6937 
6938     SetFocus(radio3);
6939     GetWindowRect(radio3, &rc);
6940 
6941     flush_events();
6942     flush_sequence();
6943 
6944     msg.hwnd = parent;
6945     msg.message = WM_KEYDOWN;
6946     msg.wParam = VK_UP;
6947     msg.lParam = 0;
6948     msg.pt.x = rc.left + 1;
6949     msg.pt.y = rc.top + 1;
6950     ret = IsDialogMessageA(parent, &msg);
6951     ok(ret, "IsDialogMessage should return TRUE\n");
6952     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6953 if (0) /* actual message sequence is different on every run in some Windows setups */
6954     ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #1", FALSE);
6955     /* what really matters is that nothing has changed */
6956     test_radio(radio1, 1, radio2, 1, radio3, 1);
6957 
6958     set_radio(radio1, 0, radio2, 1, radio3, 1);
6959     test_radio(radio1, 0, radio2, 1, radio3, 1);
6960 
6961     flush_events();
6962     flush_sequence();
6963 
6964     ret = IsDialogMessageA(parent, &msg);
6965     ok(ret, "IsDialogMessage should return TRUE\n");
6966     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6967 if (0) /* actual message sequence is different on every run in some Windows setups */
6968     ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #2", FALSE);
6969     /* what really matters is that nothing has changed */
6970     test_radio(radio1, 0, radio2, 1, radio3, 1);
6971 
6972     /* switch from radio3 ro radio1 */
6973     SetFocus(radio3);
6974     GetWindowRect(radio3, &rc);
6975 
6976     flush_events();
6977     flush_sequence();
6978 
6979     msg.hwnd = parent;
6980     msg.message = WM_KEYDOWN;
6981     msg.wParam = VK_DOWN;
6982     msg.lParam = 0;
6983     msg.pt.x = rc.left + 1;
6984     msg.pt.y = rc.top + 1;
6985     ret = IsDialogMessageA(parent, &msg);
6986     ok(ret, "IsDialogMessage should return TRUE\n");
6987     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6988     ok_sequence(auto_radio_button_VK_DOWN_dialog, "IsDialogMessage(VK_DOWN)", TRUE);
6989 
6990     test_radio(radio1, 1, radio2, 0, radio3, 0);
6991 
6992     hwnd = GetFocus();
6993     ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
6994     GetWindowRect(radio1, &rc);
6995 
6996     msg.hwnd = parent;
6997     msg.message = WM_KEYDOWN;
6998     msg.wParam = VK_DOWN;
6999     msg.lParam = 0;
7000     msg.pt.x = rc.left + 1;
7001     msg.pt.y = rc.top + 1;
7002     ret = IsDialogMessageA(parent, &msg);
7003     ok(ret, "IsDialogMessage should return TRUE\n");
7004     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7005     ok_sequence(auto_radio_button_VK_DOWN_radio3, "down to radio3", TRUE);
7006 
7007     test_radio(radio1, 1, radio2, 0, radio3, 0);
7008 
7009     hwnd = GetFocus();
7010     ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
7011 
7012     flush_events();
7013     flush_sequence();
7014 
7015     msg.hwnd = parent;
7016     msg.message = WM_KEYDOWN;
7017     msg.wParam = VK_UP;
7018     msg.lParam = 0;
7019     msg.pt.x = rc.left + 1;
7020     msg.pt.y = rc.top + 1;
7021     ret = IsDialogMessageA(parent, &msg);
7022     ok(ret, "IsDialogMessage should return TRUE\n");
7023     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7024     ok_sequence(auto_radio_button_VK_UP_radio1, "up to radio1", TRUE);
7025 
7026     test_radio(radio1, 1, radio2, 0, radio3, 0);
7027 
7028     hwnd = GetFocus();
7029     ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
7030 
7031     flush_events();
7032     flush_sequence();
7033 
7034     msg.hwnd = parent;
7035     msg.message = WM_KEYDOWN;
7036     msg.wParam = VK_UP;
7037     msg.lParam = 0;
7038     msg.pt.x = rc.left + 1;
7039     msg.pt.y = rc.top + 1;
7040     ret = IsDialogMessageA(parent, &msg);
7041     ok(ret, "IsDialogMessage should return TRUE\n");
7042     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7043 if (0) /* actual message sequence is different on every run in some Windows setups */
7044     ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #3", FALSE);
7045     /* what really matters is that nothing has changed */
7046     test_radio(radio1, 1, radio2, 0, radio3, 0);
7047 
7048     log_all_parent_messages--;
7049 
7050     DestroyWindow(parent);
7051 }
7052 
7053 /****************** static message test *************************/
7054 static const struct message WmSetFontStaticSeq2[] =
7055 {
7056     { WM_SETFONT, sent },
7057     { WM_PAINT, sent|defwinproc|optional },
7058     { WM_ERASEBKGND, sent|defwinproc|optional },
7059     { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
7060     { 0 }
7061 };
7062 
7063 static WNDPROC old_static_proc;
7064 
7065 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7066 {
7067     static LONG defwndproc_counter = 0;
7068     LRESULT ret;
7069     struct recvd_message msg;
7070 
7071     if (ignore_message( message )) return 0;
7072 
7073     msg.hwnd = hwnd;
7074     msg.message = message;
7075     msg.flags = sent|wparam|lparam;
7076     if (defwndproc_counter) msg.flags |= defwinproc;
7077     msg.wParam = wParam;
7078     msg.lParam = lParam;
7079     msg.descr = "static";
7080     add_message(&msg);
7081 
7082     defwndproc_counter++;
7083     ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
7084     defwndproc_counter--;
7085 
7086     return ret;
7087 }
7088 
7089 static void subclass_static(void)
7090 {
7091     WNDCLASSA cls;
7092 
7093     if (!GetClassInfoA(0, "static", &cls)) assert(0);
7094 
7095     old_static_proc = cls.lpfnWndProc;
7096 
7097     cls.hInstance = GetModuleHandleA(NULL);
7098     cls.lpfnWndProc = static_hook_proc;
7099     cls.lpszClassName = "my_static_class";
7100     UnregisterClassA(cls.lpszClassName, cls.hInstance);
7101     if (!RegisterClassA(&cls)) assert(0);
7102 }
7103 
7104 static void test_static_messages(void)
7105 {
7106     /* FIXME: make as comprehensive as the button message test */
7107     static const struct
7108     {
7109 	DWORD style;
7110 	DWORD dlg_code;
7111 	const struct message *setfont;
7112     } static_ctrl[] = {
7113 	{ SS_LEFT, DLGC_STATIC,
7114 	  WmSetFontStaticSeq2 }
7115     };
7116     unsigned int i;
7117     HWND hwnd;
7118     DWORD dlg_code;
7119 
7120     subclass_static();
7121 
7122     for (i = 0; i < sizeof(static_ctrl)/sizeof(static_ctrl[0]); i++)
7123     {
7124 	hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
7125 			       0, 0, 50, 14, 0, 0, 0, NULL);
7126 	ok(hwnd != 0, "Failed to create static window\n");
7127 
7128 	dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
7129 	ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
7130 
7131 	ShowWindow(hwnd, SW_SHOW);
7132 	UpdateWindow(hwnd);
7133 	SetFocus(0);
7134 	flush_sequence();
7135 
7136 	trace("static style %08x\n", static_ctrl[i].style);
7137 	SendMessageA(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
7138 	ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
7139 
7140 	DestroyWindow(hwnd);
7141     }
7142 }
7143 
7144 /****************** ComboBox message test *************************/
7145 #define ID_COMBOBOX 0x000f
7146 
7147 static const struct message SetCurSelComboSeq[] =
7148 {
7149     { CB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7150     { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7151     { LB_SETTOPINDEX, sent|wparam|lparam, 0, 0 },
7152     { LB_GETCURSEL, sent|wparam|lparam, 0, 0 },
7153     { LB_GETTEXTLEN, sent|wparam|lparam, 0, 0 },
7154     { LB_GETTEXTLEN, sent|wparam|lparam|optional, 0, 0 }, /* TODO: it's sent on all Windows versions */
7155     { LB_GETTEXT, sent|wparam, 0 },
7156     { WM_CTLCOLOREDIT, sent|parent },
7157     { LB_GETITEMDATA, sent|wparam|lparam, 0, 0 },
7158     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_COMBOBOX, 0x100010f3 },
7159     { 0 }
7160 };
7161 
7162 static const struct message SetCurSelComboSeq2[] =
7163 {
7164     { CB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7165     { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7166     { LB_SETTOPINDEX, sent|wparam|lparam, 0, 0 },
7167     { LB_GETCURSEL, sent|wparam|lparam, 0, 0 },
7168     { LB_GETTEXTLEN, sent|wparam|lparam, 0, 0 },
7169     { LB_GETTEXTLEN, sent|wparam|lparam|optional, 0, 0 }, /* TODO: it's sent on all Windows versions */
7170     { LB_GETTEXT, sent|wparam, 0 },
7171     { 0 }
7172 };
7173 
7174 static const struct message SetCurSelComboSeq_edit[] =
7175 {
7176     { CB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7177     { WM_SETTEXT, sent|wparam, 0 },
7178     { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
7179     { 0 }
7180 };
7181 
7182 static const struct message WmKeyDownComboSeq[] =
7183 {
7184     { WM_KEYDOWN, sent|wparam|lparam, VK_DOWN, 0 },
7185     { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(1000, LBN_SELCHANGE) },
7186     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDOK) },
7187     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELCHANGE) },
7188     { WM_CTLCOLOREDIT, sent|parent },
7189     { WM_KEYUP, sent|wparam|lparam, VK_DOWN, 0 },
7190     { 0 }
7191 };
7192 
7193 static const struct message WmSetPosComboSeq[] =
7194 {
7195     { WM_WINDOWPOSCHANGING, sent },
7196     { WM_NCCALCSIZE, sent|wparam, TRUE },
7197     { WM_CHILDACTIVATE, sent },
7198     { WM_WINDOWPOSCHANGED, sent },
7199     { WM_MOVE, sent|defwinproc },
7200     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
7201     { WM_WINDOWPOSCHANGING, sent|defwinproc },
7202     { WM_NCCALCSIZE, sent|defwinproc|wparam, TRUE },
7203     { WM_WINDOWPOSCHANGED, sent|defwinproc },
7204     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
7205     { 0 }
7206 };
7207 
7208 static const struct message WMSetFocusComboBoxSeq[] =
7209 {
7210     { WM_SETFOCUS, sent },
7211     { WM_KILLFOCUS, sent|parent },
7212     { WM_SETFOCUS, sent },
7213     { WM_COMMAND, sent|defwinproc|wparam, MAKEWPARAM(1001, EN_SETFOCUS) },
7214     { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, INT_MAX },
7215     { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7216     { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7217     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SETFOCUS) },
7218     { 0 }
7219 };
7220 
7221 static const struct message SetFocusButtonSeq[] =
7222 {
7223     { WM_KILLFOCUS, sent },
7224     { CB_GETCOMBOBOXINFO, sent|optional },/* Windows 2000 */
7225     { 0x0167, sent|optional },/* Undocumented message. Sent on all versions except Windows 2000 */
7226     { WM_LBUTTONUP, sent|defwinproc },
7227     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDCANCEL) },
7228     { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, 0 },
7229     { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7230     { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7231     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_KILLFOCUS) },
7232     { WM_CTLCOLORBTN, sent|parent },
7233     { 0 }
7234 };
7235 
7236 static const struct message SetFocusComboBoxSeq[] =
7237 {
7238     { WM_CTLCOLORBTN, sent|parent },
7239     { WM_SETFOCUS, sent },
7240     { WM_KILLFOCUS, sent|defwinproc },
7241     { WM_SETFOCUS, sent },
7242     { WM_COMMAND, sent|defwinproc|wparam, MAKEWPARAM(1001, EN_SETFOCUS) },
7243     { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, INT_MAX },
7244     { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7245     { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7246     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SETFOCUS) },
7247     { 0 }
7248 };
7249 
7250 static const struct message SetFocusButtonSeq2[] =
7251 {
7252     { WM_KILLFOCUS, sent },
7253     { CB_GETCOMBOBOXINFO, sent|optional },/* Windows 2000 */
7254     { 0x0167, sent|optional },/* Undocumented message. Sent on all versions except Windows 2000 */
7255     { WM_LBUTTONUP, sent|defwinproc },
7256     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDCANCEL) },
7257     { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, 0 },
7258     { WM_CTLCOLOREDIT, sent|defwinproc },
7259     { WM_CTLCOLOREDIT, sent|parent },
7260     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_KILLFOCUS) },
7261     { WM_CTLCOLORBTN, sent|parent },
7262     { 0 }
7263 };
7264 
7265 static WNDPROC old_combobox_proc, edit_window_proc, lbox_window_proc;
7266 
7267 static LRESULT CALLBACK combobox_edit_subclass_proc(HWND hwnd, UINT message,
7268         WPARAM wParam, LPARAM lParam)
7269 {
7270     static LONG defwndproc_counter = 0;
7271     LRESULT ret;
7272     struct recvd_message msg;
7273 
7274     /* do not log painting messages */
7275     if (message != WM_PAINT &&
7276         message != WM_NCPAINT &&
7277         message != WM_SYNCPAINT &&
7278         message != WM_ERASEBKGND &&
7279         message != WM_NCHITTEST &&
7280         message != WM_GETTEXT &&
7281         !ignore_message( message ))
7282     {
7283         msg.hwnd = hwnd;
7284         msg.message = message;
7285         msg.flags = sent|wparam|lparam;
7286         if (defwndproc_counter) msg.flags |= defwinproc;
7287         msg.wParam = wParam;
7288         msg.lParam = lParam;
7289         msg.descr = "combo edit";
7290         add_message(&msg);
7291     }
7292 
7293     defwndproc_counter++;
7294     ret = CallWindowProcA(edit_window_proc, hwnd, message, wParam, lParam);
7295     defwndproc_counter--;
7296 
7297     return ret;
7298 }
7299 
7300 static LRESULT CALLBACK combobox_lbox_subclass_proc(HWND hwnd, UINT message,
7301         WPARAM wParam, LPARAM lParam)
7302 {
7303     static LONG defwndproc_counter = 0;
7304     LRESULT ret;
7305     struct recvd_message msg;
7306 
7307     /* do not log painting messages */
7308     if (message != WM_PAINT &&
7309         message != WM_NCPAINT &&
7310         message != WM_SYNCPAINT &&
7311         message != WM_ERASEBKGND &&
7312         message != WM_NCHITTEST &&
7313         !ignore_message( message ))
7314     {
7315         msg.hwnd = hwnd;
7316         msg.message = message;
7317         msg.flags = sent|wparam|lparam;
7318         if (defwndproc_counter) msg.flags |= defwinproc;
7319         msg.wParam = wParam;
7320         msg.lParam = lParam;
7321         msg.descr = "combo lbox";
7322         add_message(&msg);
7323     }
7324 
7325     defwndproc_counter++;
7326     ret = CallWindowProcA(lbox_window_proc, hwnd, message, wParam, lParam);
7327     defwndproc_counter--;
7328 
7329     return ret;
7330 }
7331 
7332 static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7333 {
7334     static LONG defwndproc_counter = 0;
7335     LRESULT ret;
7336     struct recvd_message msg;
7337 
7338     /* do not log painting messages */
7339     if (message != WM_PAINT &&
7340         message != WM_NCPAINT &&
7341         message != WM_SYNCPAINT &&
7342         message != WM_ERASEBKGND &&
7343         message != WM_NCHITTEST &&
7344         message != WM_GETTEXT &&
7345         !ignore_message( message ))
7346     {
7347         msg.hwnd = hwnd;
7348         msg.message = message;
7349         msg.flags = sent|wparam|lparam;
7350         if (defwndproc_counter) msg.flags |= defwinproc;
7351         msg.wParam = wParam;
7352         msg.lParam = lParam;
7353         msg.descr = "combo";
7354         add_message(&msg);
7355     }
7356 
7357     defwndproc_counter++;
7358     ret = CallWindowProcA(old_combobox_proc, hwnd, message, wParam, lParam);
7359     defwndproc_counter--;
7360 
7361     return ret;
7362 }
7363 
7364 static void subclass_combobox(void)
7365 {
7366     WNDCLASSA cls;
7367 
7368     if (!GetClassInfoA(0, "ComboBox", &cls)) assert(0);
7369 
7370     old_combobox_proc = cls.lpfnWndProc;
7371 
7372     cls.hInstance = GetModuleHandleA(NULL);
7373     cls.lpfnWndProc = combobox_hook_proc;
7374     cls.lpszClassName = "my_combobox_class";
7375     UnregisterClassA(cls.lpszClassName, cls.hInstance);
7376     if (!RegisterClassA(&cls)) assert(0);
7377 }
7378 
7379 static void test_combobox_messages(void)
7380 {
7381     HWND parent, combo, button, edit, lbox;
7382     LRESULT ret;
7383     COMBOBOXINFO cbInfo;
7384     BOOL res;
7385 
7386     subclass_combobox();
7387 
7388     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7389                              100, 100, 200, 200, 0, 0, 0, NULL);
7390     ok(parent != 0, "Failed to create parent window\n");
7391     flush_sequence();
7392 
7393     combo = CreateWindowExA(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
7394                            0, 0, 100, 150, parent, (HMENU)ID_COMBOBOX, 0, NULL);
7395     ok(combo != 0, "Failed to create combobox window\n");
7396 
7397     UpdateWindow(combo);
7398 
7399     ret = SendMessageA(combo, WM_GETDLGCODE, 0, 0);
7400     ok(ret == (DLGC_WANTCHARS | DLGC_WANTARROWS), "wrong dlg_code %08lx\n", ret);
7401 
7402     ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
7403     ok(ret == 0, "expected 0, got %ld\n", ret);
7404     ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 1");
7405     ok(ret == 1, "expected 1, got %ld\n", ret);
7406     ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 2");
7407     ok(ret == 2, "expected 2, got %ld\n", ret);
7408 
7409     SendMessageA(combo, CB_SETCURSEL, 0, 0);
7410     SetFocus(combo);
7411     flush_sequence();
7412 
7413     log_all_parent_messages++;
7414     SendMessageA(combo, WM_KEYDOWN, VK_DOWN, 0);
7415     SendMessageA(combo, WM_KEYUP, VK_DOWN, 0);
7416     log_all_parent_messages--;
7417     ok_sequence(WmKeyDownComboSeq, "WM_KEYDOWN/VK_DOWN on a ComboBox", FALSE);
7418 
7419     flush_sequence();
7420     SetWindowPos(combo, 0, 10, 10, 120, 130, SWP_NOZORDER);
7421     ok_sequence(WmSetPosComboSeq, "repositioning messages on a ComboBox", FALSE);
7422 
7423     DestroyWindow(combo);
7424     DestroyWindow(parent);
7425 
7426     /* Start again. Test combobox text selection when getting and losing focus */
7427     parent = CreateWindowExA(0, "TestParentClass", "Parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7428                              10, 10, 300, 300, NULL, NULL, NULL, NULL);
7429     ok(parent != 0, "Failed to create parent window\n");
7430 
7431     combo = CreateWindowExA(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWN,
7432                             5, 5, 100, 100, parent, (HMENU)ID_COMBOBOX, NULL, NULL);
7433     ok(combo != 0, "Failed to create combobox window\n");
7434 
7435     cbInfo.cbSize = sizeof(COMBOBOXINFO);
7436     SetLastError(0xdeadbeef);
7437     res = GetComboBoxInfo(combo, &cbInfo);
7438     ok(res, "Failed to get COMBOBOXINFO structure; LastError: %u\n", GetLastError());
7439     edit = cbInfo.hwndItem;
7440 
7441     edit_window_proc = (WNDPROC)SetWindowLongPtrA(edit, GWLP_WNDPROC,
7442             (ULONG_PTR)combobox_edit_subclass_proc);
7443 
7444     button = CreateWindowExA(0, "Button", "OK", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
7445                              5, 50, 100, 20, parent, NULL,
7446                              (HINSTANCE)GetWindowLongPtrA(parent, GWLP_HINSTANCE), NULL);
7447     ok(button != 0, "Failed to create button window\n");
7448 
7449     flush_sequence();
7450     log_all_parent_messages++;
7451     SendMessageA(combo, WM_SETFOCUS, 0, (LPARAM)edit);
7452     log_all_parent_messages--;
7453     ok_sequence(WMSetFocusComboBoxSeq, "WM_SETFOCUS on a ComboBox", TRUE);
7454 
7455     flush_sequence();
7456     log_all_parent_messages++;
7457     SetFocus(button);
7458     log_all_parent_messages--;
7459     ok_sequence(SetFocusButtonSeq, "SetFocus on a Button", TRUE);
7460 
7461     SendMessageA(combo, WM_SETTEXT, 0, (LPARAM)"Wine Test");
7462 
7463     flush_sequence();
7464     log_all_parent_messages++;
7465     SetFocus(combo);
7466     log_all_parent_messages--;
7467     ok_sequence(SetFocusComboBoxSeq, "SetFocus on a ComboBox", TRUE);
7468 
7469     flush_sequence();
7470     log_all_parent_messages++;
7471     SetFocus(button);
7472     log_all_parent_messages--;
7473     ok_sequence(SetFocusButtonSeq2, "SetFocus on a Button (2)", TRUE);
7474 
7475     SetFocus(combo);
7476     SendMessageA(combo, WM_SETREDRAW, FALSE, 0);
7477     flush_sequence();
7478     log_all_parent_messages++;
7479     SendMessageA(combo, CB_SETCURSEL, 0, 0);
7480     log_all_parent_messages--;
7481     ok_sequence(SetCurSelComboSeq_edit, "CB_SETCURSEL on a ComboBox with edit control", FALSE);
7482 
7483     DestroyWindow(button);
7484     DestroyWindow(combo);
7485 
7486     combo = CreateWindowExA(0, "my_combobox_class", "test",
7487                             WS_CHILD | WS_VISIBLE | CBS_OWNERDRAWFIXED | CBS_DROPDOWNLIST,
7488                             5, 5, 100, 100, parent, (HMENU)ID_COMBOBOX, NULL, NULL);
7489     ok(combo != 0, "Failed to create combobox window\n");
7490 
7491     ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
7492     ok(ret == 0, "expected 0, got %ld\n", ret);
7493 
7494     cbInfo.cbSize = sizeof(COMBOBOXINFO);
7495     SetLastError(0xdeadbeef);
7496     res = GetComboBoxInfo(combo, &cbInfo);
7497     ok(res, "Failed to get COMBOBOXINFO structure; LastError: %u\n", GetLastError());
7498     lbox = cbInfo.hwndList;
7499     lbox_window_proc = (WNDPROC)SetWindowLongPtrA(lbox, GWLP_WNDPROC,
7500             (ULONG_PTR)combobox_lbox_subclass_proc);
7501     flush_sequence();
7502 
7503     log_all_parent_messages++;
7504     SendMessageA(combo, CB_SETCURSEL, 0, 0);
7505     log_all_parent_messages--;
7506     ok_sequence(SetCurSelComboSeq, "CB_SETCURSEL on a ComboBox", FALSE);
7507 
7508     ShowWindow(combo, SW_HIDE);
7509     flush_sequence();
7510     log_all_parent_messages++;
7511     SendMessageA(combo, CB_SETCURSEL, 0, 0);
7512     log_all_parent_messages--;
7513     ok_sequence(SetCurSelComboSeq2, "CB_SETCURSEL on a ComboBox", FALSE);
7514 
7515     DestroyWindow(combo);
7516     DestroyWindow(parent);
7517 }
7518 
7519 /****************** WM_IME_KEYDOWN message test *******************/
7520 
7521 static const struct message WmImeKeydownMsgSeq_0[] =
7522 {
7523     { WM_IME_KEYDOWN, wparam, VK_RETURN },
7524     { WM_CHAR, wparam, 'A' },
7525     { 0 }
7526 };
7527 
7528 static const struct message WmImeKeydownMsgSeq_1[] =
7529 {
7530     { WM_KEYDOWN, optional|wparam, VK_RETURN },
7531     { WM_CHAR,    optional|wparam, VK_RETURN },
7532     { 0 }
7533 };
7534 
7535 static LRESULT WINAPI wmime_keydown_procA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7536 {
7537     struct recvd_message msg;
7538 
7539     msg.hwnd = hwnd;
7540     msg.message = message;
7541     msg.flags = wparam|lparam;
7542     msg.wParam = wParam;
7543     msg.lParam = lParam;
7544     msg.descr = "wmime_keydown";
7545     add_message(&msg);
7546 
7547     return DefWindowProcA(hwnd, message, wParam, lParam);
7548 }
7549 
7550 static void register_wmime_keydown_class(void)
7551 {
7552     WNDCLASSA cls;
7553 
7554     ZeroMemory(&cls, sizeof(WNDCLASSA));
7555     cls.lpfnWndProc = wmime_keydown_procA;
7556     cls.hInstance = GetModuleHandleA(0);
7557     cls.lpszClassName = "wmime_keydown_class";
7558     if (!RegisterClassA(&cls)) assert(0);
7559 }
7560 
7561 static void test_wmime_keydown_message(void)
7562 {
7563     HWND hwnd;
7564     MSG msg;
7565 
7566     trace("Message sequences by WM_IME_KEYDOWN\n");
7567 
7568     register_wmime_keydown_class();
7569     hwnd = CreateWindowExA(0, "wmime_keydown_class", NULL, WS_OVERLAPPEDWINDOW,
7570                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
7571                            NULL, NULL, 0);
7572     flush_events();
7573     flush_sequence();
7574 
7575     SendMessageA(hwnd, WM_IME_KEYDOWN, VK_RETURN, 0x1c0001);
7576     SendMessageA(hwnd, WM_CHAR, 'A', 1);
7577     ok_sequence(WmImeKeydownMsgSeq_0, "WM_IME_KEYDOWN 0", FALSE);
7578 
7579     while ( PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) )
7580     {
7581         TranslateMessage(&msg);
7582         DispatchMessageA(&msg);
7583     }
7584     ok_sequence(WmImeKeydownMsgSeq_1, "WM_IME_KEYDOWN 1", FALSE);
7585 
7586     DestroyWindow(hwnd);
7587 }
7588 
7589 /************* painting message test ********************/
7590 
7591 void dump_region(HRGN hrgn)
7592 {
7593     DWORD i, size;
7594     RGNDATA *data = NULL;
7595     RECT *rect;
7596 
7597     if (!hrgn)
7598     {
7599         printf( "null region\n" );
7600         return;
7601     }
7602     if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
7603     if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
7604     GetRegionData( hrgn, size, data );
7605     printf("%d rects:", data->rdh.nCount );
7606     for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
7607         printf( " %s", wine_dbgstr_rect( rect ));
7608     printf("\n");
7609     HeapFree( GetProcessHeap(), 0, data );
7610 }
7611 
7612 static void check_update_rgn( HWND hwnd, HRGN hrgn )
7613 {
7614     INT ret;
7615     RECT r1, r2;
7616     HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
7617     HRGN update = CreateRectRgn( 0, 0, 0, 0 );
7618 
7619     ret = GetUpdateRgn( hwnd, update, FALSE );
7620     ok( ret != ERROR, "GetUpdateRgn failed\n" );
7621     if (ret == NULLREGION)
7622     {
7623         ok( !hrgn, "Update region shouldn't be empty\n" );
7624     }
7625     else
7626     {
7627         if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
7628         {
7629             ok( 0, "Regions are different\n" );
7630             if (winetest_debug > 0)
7631             {
7632                 printf( "Update region: " );
7633                 dump_region( update );
7634                 printf( "Wanted region: " );
7635                 dump_region( hrgn );
7636             }
7637         }
7638     }
7639     GetRgnBox( update, &r1 );
7640     GetUpdateRect( hwnd, &r2, FALSE );
7641     ok( EqualRect( &r1, &r2 ), "Rectangles are different: %s / %s\n", wine_dbgstr_rect( &r1 ),
7642         wine_dbgstr_rect( &r2 ));
7643 
7644     DeleteObject( tmp );
7645     DeleteObject( update );
7646 }
7647 
7648 static const struct message WmInvalidateRgn[] = {
7649     { WM_NCPAINT, sent },
7650     { WM_GETTEXT, sent|defwinproc|optional },
7651     { 0 }
7652 };
7653 
7654 static const struct message WmGetUpdateRect[] = {
7655     { WM_NCPAINT, sent },
7656     { WM_GETTEXT, sent|defwinproc|optional },
7657     { WM_PAINT, sent },
7658     { 0 }
7659 };
7660 
7661 static const struct message WmInvalidateFull[] = {
7662     { WM_NCPAINT, sent|wparam, 1 },
7663     { WM_GETTEXT, sent|defwinproc|optional },
7664     { 0 }
7665 };
7666 
7667 static const struct message WmInvalidateErase[] = {
7668     { WM_NCPAINT, sent|wparam, 1 },
7669     { WM_GETTEXT, sent|defwinproc|optional },
7670     { WM_ERASEBKGND, sent },
7671     { 0 }
7672 };
7673 
7674 static const struct message WmInvalidatePaint[] = {
7675     { WM_PAINT, sent },
7676     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
7677     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7678     { 0 }
7679 };
7680 
7681 static const struct message WmInvalidateErasePaint[] = {
7682     { WM_PAINT, sent },
7683     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
7684     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7685     { WM_ERASEBKGND, sent|beginpaint|optional },
7686     { 0 }
7687 };
7688 
7689 static const struct message WmInvalidateErasePaint2[] = {
7690     { WM_PAINT, sent },
7691     { WM_NCPAINT, sent|beginpaint },
7692     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7693     { WM_ERASEBKGND, sent|beginpaint|optional },
7694     { 0 }
7695 };
7696 
7697 static const struct message WmErase[] = {
7698     { WM_ERASEBKGND, sent },
7699     { 0 }
7700 };
7701 
7702 static const struct message WmPaint[] = {
7703     { WM_PAINT, sent },
7704     { 0 }
7705 };
7706 
7707 static const struct message WmParentOnlyPaint[] = {
7708     { WM_PAINT, sent|parent },
7709     { 0 }
7710 };
7711 
7712 static const struct message WmInvalidateParent[] = {
7713     { WM_NCPAINT, sent|parent },
7714     { WM_GETTEXT, sent|defwinproc|parent|optional },
7715     { WM_ERASEBKGND, sent|parent },
7716     { 0 }
7717 };
7718 
7719 static const struct message WmInvalidateParentChild[] = {
7720     { WM_NCPAINT, sent|parent },
7721     { WM_GETTEXT, sent|defwinproc|parent|optional },
7722     { WM_ERASEBKGND, sent|parent },
7723     { WM_NCPAINT, sent },
7724     { WM_GETTEXT, sent|defwinproc|optional },
7725     { WM_ERASEBKGND, sent },
7726     { 0 }
7727 };
7728 
7729 static const struct message WmInvalidateParentChild2[] = {
7730     { WM_ERASEBKGND, sent|parent },
7731     { WM_NCPAINT, sent },
7732     { WM_GETTEXT, sent|defwinproc|optional },
7733     { WM_ERASEBKGND, sent },
7734     { 0 }
7735 };
7736 
7737 static const struct message WmParentPaint[] = {
7738     { WM_PAINT, sent|parent },
7739     { WM_PAINT, sent },
7740     { 0 }
7741 };
7742 
7743 static const struct message WmParentPaintNc[] = {
7744     { WM_PAINT, sent|parent },
7745     { WM_PAINT, sent },
7746     { WM_NCPAINT, sent|beginpaint },
7747     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7748     { WM_ERASEBKGND, sent|beginpaint|optional },
7749     { 0 }
7750 };
7751 
7752 static const struct message WmChildPaintNc[] = {
7753     { WM_PAINT, sent },
7754     { WM_NCPAINT, sent|beginpaint },
7755     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7756     { WM_ERASEBKGND, sent|beginpaint|optional },
7757     { 0 }
7758 };
7759 
7760 static const struct message WmParentErasePaint[] = {
7761     { WM_PAINT, sent|parent },
7762     { WM_NCPAINT, sent|parent|beginpaint },
7763     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
7764     { WM_ERASEBKGND, sent|parent|beginpaint|optional },
7765     { WM_PAINT, sent },
7766     { WM_NCPAINT, sent|beginpaint },
7767     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7768     { WM_ERASEBKGND, sent|beginpaint|optional },
7769     { 0 }
7770 };
7771 
7772 static const struct message WmParentOnlyNcPaint[] = {
7773     { WM_PAINT, sent|parent },
7774     { WM_NCPAINT, sent|parent|beginpaint },
7775     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
7776     { 0 }
7777 };
7778 
7779 static const struct message WmSetParentStyle[] = {
7780     { WM_STYLECHANGING, sent|parent },
7781     { WM_STYLECHANGED, sent|parent },
7782     { 0 }
7783 };
7784 
7785 static void test_paint_messages(void)
7786 {
7787     BOOL ret;
7788     RECT rect, rect2;
7789     POINT pt;
7790     MSG msg;
7791     HWND hparent, hchild;
7792     HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
7793     HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
7794     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
7795                                 100, 100, 200, 200, 0, 0, 0, NULL);
7796     ok (hwnd != 0, "Failed to create overlapped window\n");
7797 
7798     ShowWindow( hwnd, SW_SHOW );
7799     UpdateWindow( hwnd );
7800     flush_events();
7801     flush_sequence();
7802 
7803     check_update_rgn( hwnd, 0 );
7804     SetRectRgn( hrgn, 10, 10, 20, 20 );
7805     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
7806     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7807     check_update_rgn( hwnd, hrgn );
7808     SetRectRgn( hrgn2, 20, 20, 30, 30 );
7809     ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
7810     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7811     CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
7812     check_update_rgn( hwnd, hrgn );
7813     /* validate everything */
7814     ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7815     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7816     check_update_rgn( hwnd, 0 );
7817 
7818     /* test empty region */
7819     SetRectRgn( hrgn, 10, 10, 10, 15 );
7820     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
7821     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7822     check_update_rgn( hwnd, 0 );
7823     /* test empty rect */
7824     SetRect( &rect, 10, 10, 10, 15 );
7825     ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
7826     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7827     check_update_rgn( hwnd, 0 );
7828 
7829     /* flush pending messages */
7830     flush_events();
7831     flush_sequence();
7832 
7833     GetClientRect( hwnd, &rect );
7834     SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
7835     /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
7836      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
7837      */
7838     trace("testing InvalidateRect(0, NULL, FALSE)\n");
7839     SetRectEmpty( &rect );
7840     ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) should fail\n");
7841     check_update_rgn( hwnd, hrgn );
7842     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
7843     flush_events();
7844     ok_sequence( WmPaint, "Paint", FALSE );
7845     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7846     check_update_rgn( hwnd, 0 );
7847 
7848     /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
7849      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
7850      */
7851     trace("testing ValidateRect(0, NULL)\n");
7852     SetRectEmpty( &rect );
7853     if (ValidateRect(0, &rect) && /* not supported on Win9x */
7854         GetUpdateRect(hwnd, NULL, FALSE))  /* or >= Win 8 */
7855     {
7856         check_update_rgn( hwnd, hrgn );
7857         ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
7858         flush_events();
7859         ok_sequence( WmPaint, "Paint", FALSE );
7860         RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7861         check_update_rgn( hwnd, 0 );
7862     }
7863 
7864     trace("testing InvalidateRgn(0, NULL, FALSE)\n");
7865     SetLastError(0xdeadbeef);
7866     ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
7867     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef,
7868        "wrong error code %d\n", GetLastError());
7869     check_update_rgn( hwnd, 0 );
7870     flush_events();
7871     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
7872 
7873     trace("testing ValidateRgn(0, NULL)\n");
7874     SetLastError(0xdeadbeef);
7875     ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
7876     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
7877        broken( GetLastError() == 0xdeadbeef ) /* win9x */,
7878        "wrong error code %d\n", GetLastError());
7879     check_update_rgn( hwnd, 0 );
7880     flush_events();
7881     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
7882 
7883     trace("testing UpdateWindow(NULL)\n");
7884     SetLastError(0xdeadbeef);
7885     ok(!UpdateWindow(NULL), "UpdateWindow(NULL) should fail\n");
7886     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
7887        broken( GetLastError() == 0xdeadbeef ) /* win9x */,
7888        "wrong error code %d\n", GetLastError());
7889     check_update_rgn( hwnd, 0 );
7890     flush_events();
7891     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
7892 
7893     /* now with frame */
7894     SetRectRgn( hrgn, -5, -5, 20, 20 );
7895 
7896     /* flush pending messages */
7897     flush_events();
7898     flush_sequence();
7899     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
7900     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
7901 
7902     SetRectRgn( hrgn, 0, 0, 20, 20 );  /* GetUpdateRgn clips to client area */
7903     check_update_rgn( hwnd, hrgn );
7904 
7905     flush_sequence();
7906     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
7907     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
7908 
7909     flush_sequence();
7910     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
7911     ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
7912 
7913     GetClientRect( hwnd, &rect );
7914     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
7915     check_update_rgn( hwnd, hrgn );
7916 
7917     flush_sequence();
7918     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
7919     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
7920 
7921     flush_sequence();
7922     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
7923     ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
7924     check_update_rgn( hwnd, 0 );
7925 
7926     flush_sequence();
7927     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
7928     ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
7929     check_update_rgn( hwnd, 0 );
7930 
7931     flush_sequence();
7932     SetRectRgn( hrgn, 0, 0, 100, 100 );
7933     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
7934     SetRectRgn( hrgn, 0, 0, 50, 100 );
7935     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
7936     SetRectRgn( hrgn, 50, 0, 100, 100 );
7937     check_update_rgn( hwnd, hrgn );
7938     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
7939     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );  /* must not generate messages, everything is valid */
7940     check_update_rgn( hwnd, 0 );
7941 
7942     flush_sequence();
7943     SetRectRgn( hrgn, 0, 0, 100, 100 );
7944     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
7945     SetRectRgn( hrgn, 0, 0, 100, 50 );
7946     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
7947     ok_sequence( WmErase, "Erase", FALSE );
7948     SetRectRgn( hrgn, 0, 50, 100, 100 );
7949     check_update_rgn( hwnd, hrgn );
7950 
7951     flush_sequence();
7952     SetRectRgn( hrgn, 0, 0, 100, 100 );
7953     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
7954     SetRectRgn( hrgn, 0, 0, 50, 50 );
7955     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
7956     ok_sequence( WmPaint, "Paint", FALSE );
7957 
7958     flush_sequence();
7959     SetRectRgn( hrgn, -4, -4, -2, -2 );
7960     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
7961     SetRectRgn( hrgn, -200, -200, -198, -198 );
7962     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
7963     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
7964 
7965     flush_sequence();
7966     SetRectRgn( hrgn, -4, -4, -2, -2 );
7967     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
7968     SetRectRgn( hrgn, -4, -4, -3, -3 );
7969     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
7970     SetRectRgn( hrgn, 0, 0, 1, 1 );
7971     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
7972     ok_sequence( WmPaint, "Paint", FALSE );
7973 
7974     flush_sequence();
7975     SetRectRgn( hrgn, -4, -4, -1, -1 );
7976     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
7977     RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
7978     /* make sure no WM_PAINT was generated */
7979     flush_events();
7980     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
7981 
7982     flush_sequence();
7983     SetRectRgn( hrgn, -4, -4, -1, -1 );
7984     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
7985     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
7986     {
7987         if (msg.hwnd == hwnd && msg.message == WM_PAINT)
7988         {
7989             /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
7990             INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
7991             ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
7992             ret = GetUpdateRect( hwnd, &rect, FALSE );
7993             ok( ret, "Invalid GetUpdateRect result %d\n", ret );
7994             /* this will send WM_NCPAINT and validate the non client area */
7995             ret = GetUpdateRect( hwnd, &rect, TRUE );
7996             ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
7997         }
7998         DispatchMessageA( &msg );
7999     }
8000     ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
8001 
8002     DestroyWindow( hwnd );
8003 
8004     /* now test with a child window */
8005 
8006     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
8007                               100, 100, 200, 200, 0, 0, 0, NULL);
8008     ok (hparent != 0, "Failed to create parent window\n");
8009 
8010     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
8011                            10, 10, 100, 100, hparent, 0, 0, NULL);
8012     ok (hchild != 0, "Failed to create child window\n");
8013 
8014     ShowWindow( hparent, SW_SHOW );
8015     UpdateWindow( hparent );
8016     UpdateWindow( hchild );
8017     flush_events();
8018     flush_sequence();
8019     log_all_parent_messages++;
8020 
8021     SetRect( &rect, 0, 0, 50, 50 );
8022     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8023     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
8024     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
8025 
8026     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8027     pt.x = pt.y = 0;
8028     MapWindowPoints( hchild, hparent, &pt, 1 );
8029     SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
8030     check_update_rgn( hchild, hrgn );
8031     SetRectRgn( hrgn, 0, 0, 50, 50 );
8032     check_update_rgn( hparent, hrgn );
8033     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8034     ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
8035     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
8036     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
8037 
8038     flush_events();
8039     ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
8040 
8041     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
8042     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8043     ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
8044     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
8045     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
8046 
8047     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
8048     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
8049     ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
8050 
8051     SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
8052     flush_sequence();
8053     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
8054     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8055     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
8056 
8057     /* flush all paint messages */
8058     flush_events();
8059     flush_sequence();
8060 
8061     /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
8062     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
8063     SetRectRgn( hrgn, 0, 0, 50, 50 );
8064     check_update_rgn( hparent, hrgn );
8065     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
8066     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8067     SetRectRgn( hrgn, 0, 0, 50, 50 );
8068     check_update_rgn( hparent, hrgn );
8069 
8070     /* flush all paint messages */
8071     flush_events();
8072     SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
8073     flush_sequence();
8074 
8075     /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
8076     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8077     SetRectRgn( hrgn, 0, 0, 50, 50 );
8078     check_update_rgn( hparent, hrgn );
8079     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
8080     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8081     SetRectRgn( hrgn2, 10, 10, 50, 50 );
8082     CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
8083     check_update_rgn( hparent, hrgn );
8084     /* flush all paint messages */
8085     flush_events();
8086     flush_sequence();
8087 
8088     /* same as above but parent gets completely validated */
8089     SetRect( &rect, 20, 20, 30, 30 );
8090     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8091     SetRectRgn( hrgn, 20, 20, 30, 30 );
8092     check_update_rgn( hparent, hrgn );
8093     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
8094     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8095     check_update_rgn( hparent, 0 );  /* no update region */
8096     flush_events();
8097     ok_sequence( WmEmptySeq, "WmEmpty", FALSE );  /* and no paint messages */
8098 
8099     /* make sure RDW_VALIDATE on child doesn't have the same effect */
8100     flush_sequence();
8101     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8102     SetRectRgn( hrgn, 20, 20, 30, 30 );
8103     check_update_rgn( hparent, hrgn );
8104     RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
8105     SetRectRgn( hrgn, 20, 20, 30, 30 );
8106     check_update_rgn( hparent, hrgn );
8107 
8108     /* same as above but normal WM_PAINT doesn't validate parent */
8109     flush_sequence();
8110     SetRect( &rect, 20, 20, 30, 30 );
8111     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8112     SetRectRgn( hrgn, 20, 20, 30, 30 );
8113     check_update_rgn( hparent, hrgn );
8114     /* no WM_PAINT in child while parent still pending */
8115     while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8116     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8117     while (PeekMessageA( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8118     ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
8119 
8120     flush_sequence();
8121     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8122     /* no WM_PAINT in child while parent still pending */
8123     while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8124     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8125     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
8126     /* now that parent is valid child should get WM_PAINT */
8127     while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8128     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8129     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8130     ok_sequence( WmEmptySeq, "No other message", FALSE );
8131 
8132     /* same thing with WS_CLIPCHILDREN in parent */
8133     flush_sequence();
8134     SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
8135     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
8136     /* changing style invalidates non client area, but we need to invalidate something else to see it */
8137     RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
8138     ok_sequence( WmEmptySeq, "No message", FALSE );
8139     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
8140     ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
8141 
8142     flush_sequence();
8143     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
8144     SetRectRgn( hrgn, 20, 20, 30, 30 );
8145     check_update_rgn( hparent, hrgn );
8146     /* no WM_PAINT in child while parent still pending */
8147     while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8148     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8149     /* WM_PAINT in parent first */
8150     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8151     ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
8152 
8153     /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
8154     flush_sequence();
8155     SetRect( &rect, 0, 0, 30, 30 );
8156     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
8157     SetRectRgn( hrgn, 0, 0, 30, 30 );
8158     check_update_rgn( hparent, hrgn );
8159     flush_events();
8160     ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
8161 
8162     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
8163     flush_sequence();
8164     SetRect( &rect, -10, 0, 30, 30 );
8165     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
8166     SetRect( &rect, 0, 0, 20, 20 );
8167     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
8168     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
8169     ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
8170 
8171     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
8172     flush_sequence();
8173     SetRect( &rect, -10, 0, 30, 30 );
8174     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
8175     SetRect( &rect, 0, 0, 100, 100 );
8176     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
8177     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
8178     ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
8179     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8180     ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
8181 
8182     /* WS_CLIPCHILDREN doesn't exclude children from update region */
8183     flush_sequence();
8184     RedrawWindow( hparent, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
8185     GetClientRect( hparent, &rect );
8186     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8187     check_update_rgn( hparent, hrgn );
8188     flush_events();
8189 
8190     RedrawWindow( hparent, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
8191     GetClientRect( hparent, &rect );
8192     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8193     check_update_rgn( hparent, hrgn );
8194     flush_events();
8195 
8196     /* test RDW_INTERNALPAINT behavior */
8197 
8198     flush_sequence();
8199     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
8200     flush_events();
8201     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
8202 
8203     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
8204     flush_events();
8205     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
8206 
8207     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
8208     flush_events();
8209     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
8210 
8211     assert( GetWindowLongA(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
8212     UpdateWindow( hparent );
8213     flush_events();
8214     flush_sequence();
8215     trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
8216     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8217     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
8218                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8219     flush_events();
8220     ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
8221 
8222     UpdateWindow( hparent );
8223     flush_events();
8224     flush_sequence();
8225     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
8226     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8227     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
8228                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8229     flush_events();
8230     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
8231 
8232     SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
8233     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
8234     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
8235     flush_events();
8236     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
8237 
8238     assert( !(GetWindowLongA(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
8239     UpdateWindow( hparent );
8240     flush_events();
8241     flush_sequence();
8242     trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
8243     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8244     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
8245                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8246     flush_events();
8247     ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
8248 
8249     UpdateWindow( hparent );
8250     flush_events();
8251     flush_sequence();
8252     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
8253     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8254     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
8255                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8256     flush_events();
8257     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
8258 
8259     ok(GetWindowLongA( hparent, GWL_STYLE ) & WS_VISIBLE, "parent should be visible\n");
8260     ok(GetWindowLongA( hchild, GWL_STYLE ) & WS_VISIBLE, "child should be visible\n");
8261 
8262     UpdateWindow( hparent );
8263     flush_events();
8264     flush_sequence();
8265     trace("testing SetWindowPos(-10000, -10000) on child\n");
8266     SetWindowPos( hchild, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
8267     check_update_rgn( hchild, 0 );
8268     flush_events();
8269 
8270 #if 0 /* this one doesn't pass under Wine yet */
8271     UpdateWindow( hparent );
8272     flush_events();
8273     flush_sequence();
8274     trace("testing ShowWindow(SW_MINIMIZE) on child\n");
8275     ShowWindow( hchild, SW_MINIMIZE );
8276     check_update_rgn( hchild, 0 );
8277     flush_events();
8278 #endif
8279 
8280     UpdateWindow( hparent );
8281     flush_events();
8282     flush_sequence();
8283     trace("testing SetWindowPos(-10000, -10000) on parent\n");
8284     SetWindowPos( hparent, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
8285     check_update_rgn( hparent, 0 );
8286     flush_events();
8287 
8288     log_all_parent_messages--;
8289     DestroyWindow( hparent );
8290     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
8291 
8292     /* tests for moving windows off-screen (needs simple WS_POPUP windows) */
8293 
8294     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_POPUP | WS_VISIBLE,
8295                               100, 100, 200, 200, 0, 0, 0, NULL);
8296     ok (hparent != 0, "Failed to create parent window\n");
8297 
8298     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
8299                            10, 10, 100, 100, hparent, 0, 0, NULL);
8300     ok (hchild != 0, "Failed to create child window\n");
8301 
8302     ShowWindow( hparent, SW_SHOW );
8303     UpdateWindow( hparent );
8304     UpdateWindow( hchild );
8305     flush_events();
8306     flush_sequence();
8307 
8308     /* moving child outside of parent boundaries changes update region */
8309     SetRect( &rect, 0, 0, 40, 40 );
8310     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
8311     SetRectRgn( hrgn, 0, 0, 40, 40 );
8312     check_update_rgn( hchild, hrgn );
8313     MoveWindow( hchild, -10, 10, 100, 100, FALSE );
8314     SetRectRgn( hrgn, 10, 0, 40, 40 );
8315     check_update_rgn( hchild, hrgn );
8316     MoveWindow( hchild, -10, -10, 100, 100, FALSE );
8317     SetRectRgn( hrgn, 10, 10, 40, 40 );
8318     check_update_rgn( hchild, hrgn );
8319 
8320     /* moving parent off-screen does too */
8321     SetRect( &rect, 0, 0, 100, 100 );
8322     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
8323     SetRectRgn( hrgn, 0, 0, 100, 100 );
8324     check_update_rgn( hparent, hrgn );
8325     SetRectRgn( hrgn, 10, 10, 40, 40 );
8326     check_update_rgn( hchild, hrgn );
8327     MoveWindow( hparent, -20, -20, 200, 200, FALSE );
8328     GetUpdateRect( hparent, &rect2, FALSE );
8329     if (!EqualRect( &rect2, &rect )) /* Win 8 and later don't crop update to screen */
8330     {
8331         rect.left += 20;
8332         rect.top += 20;
8333     }
8334     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8335     check_update_rgn( hparent, hrgn );
8336     SetRectRgn( hrgn, rect.left + 10, rect.top + 10, 40, 40 );
8337     check_update_rgn( hchild, hrgn );
8338 
8339     /* invalidated region is cropped by the parent rects */
8340     SetRect( &rect, 0, 0, 50, 50 );
8341     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
8342     SetRectRgn( hrgn, rect2.left + 10, rect2.top + 10, 50, 50 );
8343     check_update_rgn( hchild, hrgn );
8344 
8345     DestroyWindow( hparent );
8346     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
8347     flush_sequence();
8348 
8349     DeleteObject( hrgn );
8350     DeleteObject( hrgn2 );
8351 }
8352 
8353 struct wnd_event
8354 {
8355     HWND hwnd;
8356     HANDLE grand_child;
8357     HANDLE start_event;
8358     HANDLE stop_event;
8359 };
8360 
8361 static DWORD WINAPI thread_proc(void *param)
8362 {
8363     MSG msg;
8364     struct wnd_event *wnd_event = param;
8365 
8366     wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
8367                                       100, 100, 200, 200, 0, 0, 0, NULL);
8368     ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
8369 
8370     SetEvent(wnd_event->start_event);
8371 
8372     while (GetMessageA(&msg, 0, 0, 0))
8373     {
8374 	TranslateMessage(&msg);
8375 	DispatchMessageA(&msg);
8376     }
8377 
8378     ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
8379 
8380     return 0;
8381 }
8382 
8383 static DWORD CALLBACK create_grand_child_thread( void *param )
8384 {
8385     struct wnd_event *wnd_event = param;
8386     HWND hchild;
8387     MSG msg;
8388 
8389     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
8390                              WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
8391     ok (hchild != 0, "Failed to create child window\n");
8392     flush_events();
8393     flush_sequence();
8394     SetEvent( wnd_event->start_event );
8395 
8396     for (;;)
8397     {
8398         MsgWaitForMultipleObjects(0, NULL, FALSE, 1000, QS_ALLINPUT);
8399         if (!IsWindow( hchild )) break;  /* will be destroyed when parent thread exits */
8400         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8401     }
8402     return 0;
8403 }
8404 
8405 static DWORD CALLBACK create_child_thread( void *param )
8406 {
8407     struct wnd_event *wnd_event = param;
8408     struct wnd_event child_event;
8409     DWORD ret, tid;
8410     MSG msg;
8411 
8412     child_event.hwnd = CreateWindowExA(0, "TestWindowClass", "Test child",
8413                              WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
8414     ok (child_event.hwnd != 0, "Failed to create child window\n");
8415     SetFocus( child_event.hwnd );
8416     flush_events();
8417     flush_sequence();
8418     child_event.start_event = wnd_event->start_event;
8419     wnd_event->grand_child = CreateThread(NULL, 0, create_grand_child_thread, &child_event, 0, &tid);
8420     for (;;)
8421     {
8422         DWORD ret = MsgWaitForMultipleObjects(1, &child_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
8423         if (ret != 1) break;
8424         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8425     }
8426     ret = WaitForSingleObject( wnd_event->stop_event, 5000 );
8427     ok( !ret, "WaitForSingleObject failed %x\n", ret );
8428     return 0;
8429 }
8430 
8431 static const char manifest_dep[] =
8432 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
8433 "<assemblyIdentity version=\"1.2.3.4\"  name=\"testdep1\" type=\"win32\" processorArchitecture=\"" ARCH "\"/>"
8434 "    <file name=\"testdep.dll\" />"
8435 "</assembly>";
8436 
8437 static const char manifest_main[] =
8438 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
8439 "<assemblyIdentity version=\"1.2.3.4\" name=\"Wine.Test\" type=\"win32\" />"
8440 "<dependency>"
8441 " <dependentAssembly>"
8442 "  <assemblyIdentity type=\"win32\" name=\"testdep1\" version=\"1.2.3.4\" processorArchitecture=\"" ARCH "\" />"
8443 " </dependentAssembly>"
8444 "</dependency>"
8445 "</assembly>";
8446 
8447 static void create_manifest_file(const char *filename, const char *manifest)
8448 {
8449     WCHAR path[MAX_PATH];
8450     HANDLE file;
8451     DWORD size;
8452 
8453     MultiByteToWideChar( CP_ACP, 0, filename, -1, path, MAX_PATH );
8454     file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8455     ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
8456     WriteFile(file, manifest, strlen(manifest), &size, NULL);
8457     CloseHandle(file);
8458 }
8459 
8460 static HANDLE test_create(const char *file)
8461 {
8462     WCHAR path[MAX_PATH];
8463     ACTCTXW actctx;
8464     HANDLE handle;
8465 
8466     MultiByteToWideChar(CP_ACP, 0, file, -1, path, MAX_PATH);
8467     memset(&actctx, 0, sizeof(ACTCTXW));
8468     actctx.cbSize = sizeof(ACTCTXW);
8469     actctx.lpSource = path;
8470 
8471     handle = pCreateActCtxW(&actctx);
8472     ok(handle != INVALID_HANDLE_VALUE, "failed to create context, error %u\n", GetLastError());
8473 
8474     ok(actctx.cbSize == sizeof(actctx), "cbSize=%d\n", actctx.cbSize);
8475     ok(actctx.dwFlags == 0, "dwFlags=%d\n", actctx.dwFlags);
8476     ok(actctx.lpSource == path, "lpSource=%p\n", actctx.lpSource);
8477     ok(actctx.wProcessorArchitecture == 0, "wProcessorArchitecture=%d\n", actctx.wProcessorArchitecture);
8478     ok(actctx.wLangId == 0, "wLangId=%d\n", actctx.wLangId);
8479     ok(actctx.lpAssemblyDirectory == NULL, "lpAssemblyDirectory=%p\n", actctx.lpAssemblyDirectory);
8480     ok(actctx.lpResourceName == NULL, "lpResourceName=%p\n", actctx.lpResourceName);
8481     ok(actctx.lpApplicationName == NULL, "lpApplicationName=%p\n", actctx.lpApplicationName);
8482     ok(actctx.hModule == NULL, "hModule=%p\n", actctx.hModule);
8483 
8484     return handle;
8485 }
8486 
8487 static void test_interthread_messages(void)
8488 {
8489     HANDLE hThread, context, handle, event;
8490     ULONG_PTR cookie;
8491     DWORD tid;
8492     WNDPROC proc;
8493     MSG msg;
8494     char buf[256];
8495     int len, expected_len;
8496     struct wnd_event wnd_event;
8497     BOOL ret;
8498 
8499     wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
8500     if (!wnd_event.start_event)
8501     {
8502         win_skip("skipping interthread message test under win9x\n");
8503         return;
8504     }
8505 
8506     hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
8507     ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
8508 
8509     ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8510 
8511     CloseHandle(wnd_event.start_event);
8512 
8513     SetLastError(0xdeadbeef);
8514     ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeeded\n");
8515     ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == 0xdeadbeef,
8516        "wrong error code %d\n", GetLastError());
8517 
8518     proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
8519     ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %d\n", GetLastError());
8520 
8521     expected_len = lstrlenA("window caption text");
8522     memset(buf, 0, sizeof(buf));
8523     SetLastError(0xdeadbeef);
8524     len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
8525     ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %d, len %d, expected len %d\n", GetLastError(), len, expected_len);
8526     ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
8527 
8528     msg.hwnd = wnd_event.hwnd;
8529     msg.message = WM_GETTEXT;
8530     msg.wParam = sizeof(buf);
8531     msg.lParam = (LPARAM)buf;
8532     memset(buf, 0, sizeof(buf));
8533     SetLastError(0xdeadbeef);
8534     len = DispatchMessageA(&msg);
8535     ok((!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY) || broken(len), /* nt4 */
8536        "DispatchMessageA(WM_GETTEXT) succeeded on another thread window: ret %d, error %d\n", len, GetLastError());
8537 
8538     /* the following test causes an exception in user.exe under win9x */
8539     msg.hwnd = wnd_event.hwnd;
8540     msg.message = WM_TIMER;
8541     msg.wParam = 0;
8542     msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
8543     SetLastError(0xdeadbeef);
8544     len = DispatchMessageA(&msg);
8545     ok(!len && GetLastError() == 0xdeadbeef,
8546        "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %d\n", len, GetLastError());
8547 
8548     ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
8549     ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
8550 
8551     ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8552     CloseHandle(hThread);
8553 
8554     ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
8555 
8556     wnd_event.hwnd = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8557                               100, 100, 200, 200, 0, 0, 0, NULL);
8558     ok (wnd_event.hwnd != 0, "Failed to create parent window\n");
8559     flush_events();
8560     flush_sequence();
8561     log_all_parent_messages++;
8562     wnd_event.start_event = CreateEventA( NULL, TRUE, FALSE, NULL );
8563     wnd_event.stop_event = CreateEventA( NULL, TRUE, FALSE, NULL );
8564     hThread = CreateThread( NULL, 0, create_child_thread, &wnd_event, 0, &tid );
8565     for (;;)
8566     {
8567         ret = MsgWaitForMultipleObjects(1, &wnd_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
8568         if (ret != 1) break;
8569         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8570     }
8571     ok( !ret, "MsgWaitForMultipleObjects failed %x\n", ret );
8572     /* now wait for the thread without processing messages; this shouldn't deadlock */
8573     SetEvent( wnd_event.stop_event );
8574     ret = WaitForSingleObject( hThread, 5000 );
8575     ok( !ret, "WaitForSingleObject failed %x\n", ret );
8576     CloseHandle( hThread );
8577 
8578     ret = WaitForSingleObject( wnd_event.grand_child, 5000 );
8579     ok( !ret, "WaitForSingleObject failed %x\n", ret );
8580     CloseHandle( wnd_event.grand_child );
8581 
8582     CloseHandle( wnd_event.start_event );
8583     CloseHandle( wnd_event.stop_event );
8584     flush_events();
8585     ok_sequence(WmExitThreadSeq, "destroy child on thread exit", FALSE);
8586     log_all_parent_messages--;
8587     DestroyWindow( wnd_event.hwnd );
8588 
8589     /* activation context tests */
8590     if (!pActivateActCtx)
8591     {
8592         win_skip("Activation contexts are not supported, skipping\n");
8593         return;
8594     }
8595 
8596     create_manifest_file("testdep1.manifest", manifest_dep);
8597     create_manifest_file("main.manifest", manifest_main);
8598 
8599     context = test_create("main.manifest");
8600     DeleteFileA("testdep1.manifest");
8601     DeleteFileA("main.manifest");
8602 
8603     handle = (void*)0xdeadbeef;
8604     ret = pGetCurrentActCtx(&handle);
8605     ok(ret, "GetCurrentActCtx failed: %u\n", GetLastError());
8606     ok(handle == 0, "active context %p\n", handle);
8607 
8608     wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
8609     hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
8610     ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
8611     ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8612     CloseHandle(wnd_event.start_event);
8613 
8614     /* context is activated after thread creation, so it doesn't inherit it by default */
8615     ret = pActivateActCtx(context, &cookie);
8616     ok(ret, "activation failed: %u\n", GetLastError());
8617 
8618     handle = 0;
8619     ret = pGetCurrentActCtx(&handle);
8620     ok(ret, "GetCurrentActCtx failed: %u\n", GetLastError());
8621     ok(handle != 0, "active context %p\n", handle);
8622     pReleaseActCtx(handle);
8623 
8624     /* destination window will test for active context */
8625     ret = SendMessageA(wnd_event.hwnd, WM_USER+10, 0, 0);
8626     ok(ret, "thread window returned %d\n", ret);
8627 
8628     event = CreateEventW(NULL, 0, 0, NULL);
8629     ret = PostMessageA(wnd_event.hwnd, WM_USER+10, 0, (LPARAM)event);
8630     ok(ret, "thread window returned %d\n", ret);
8631     ok(WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8632     CloseHandle(event);
8633 
8634     ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
8635     ok(ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
8636 
8637     ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8638     CloseHandle(hThread);
8639 
8640     ret = pDeactivateActCtx(0, cookie);
8641     ok(ret, "DeactivateActCtx failed: %u\n", GetLastError());
8642     pReleaseActCtx(context);
8643 }
8644 
8645 
8646 static const struct message WmVkN[] = {
8647     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8648     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8649     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
8650     { WM_CHAR, wparam|lparam, 'n', 1 },
8651     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
8652     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8653     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8654     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8655     { 0 }
8656 };
8657 static const struct message WmShiftVkN[] = {
8658     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
8659     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
8660     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
8661     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8662     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8663     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
8664     { WM_CHAR, wparam|lparam, 'N', 1 },
8665     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
8666     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8667     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8668     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8669     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
8670     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
8671     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
8672     { 0 }
8673 };
8674 static const struct message WmCtrlVkN[] = {
8675     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8676     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8677     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8678     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8679     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8680     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
8681     { WM_CHAR, wparam|lparam, 0x000e, 1 },
8682     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
8683     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8684     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8685     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8686     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8687     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8688     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8689     { 0 }
8690 };
8691 static const struct message WmCtrlVkN_2[] = {
8692     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8693     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8694     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8695     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8696     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8697     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
8698     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8699     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8700     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8701     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8702     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8703     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8704     { 0 }
8705 };
8706 static const struct message WmAltVkN[] = {
8707     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8708     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8709     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8710     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8711     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
8712     { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
8713     { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
8714     { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
8715     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
8716     { HCBT_SYSCOMMAND, hook },
8717     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8718     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8719     { 0x00AE, sent|defwinproc|optional }, /* XP */
8720     { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
8721     { WM_INITMENU, sent|defwinproc },
8722     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8723     { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
8724     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8725     { WM_CAPTURECHANGED, sent|defwinproc },
8726     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
8727     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8728     { WM_EXITMENULOOP, sent|defwinproc },
8729     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
8730     { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
8731     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8732     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
8733     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8734     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8735     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8736     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8737     { 0 }
8738 };
8739 static const struct message WmAltVkN_2[] = {
8740     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8741     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8742     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8743     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8744     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
8745     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
8746     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8747     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
8748     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8749     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8750     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8751     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8752     { 0 }
8753 };
8754 static const struct message WmCtrlAltVkN[] = {
8755     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8756     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8757     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8758     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8759     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8760     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8761     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8762     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
8763     { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
8764     { WM_CHAR, optional },
8765     { WM_CHAR, sent|optional },
8766     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8767     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
8768     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8769     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8770     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8771     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8772     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8773     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8774     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8775     { 0 }
8776 };
8777 static const struct message WmCtrlShiftVkN[] = {
8778     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8779     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8780     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8781     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
8782     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
8783     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
8784     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8785     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8786     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
8787     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8788     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8789     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8790     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
8791     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
8792     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
8793     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8794     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8795     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8796     { 0 }
8797 };
8798 static const struct message WmCtrlAltShiftVkN[] = {
8799     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8800     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8801     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8802     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8803     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8804     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8805     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
8806     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
8807     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
8808     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8809     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
8810     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
8811     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8812     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
8813     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8814     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
8815     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
8816     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
8817     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8818     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8819     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8820     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8821     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8822     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8823     { 0 }
8824 };
8825 static const struct message WmAltPressRelease[] = {
8826     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8827     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8828     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8829     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8830     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8831     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8832     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
8833     { HCBT_SYSCOMMAND, hook },
8834     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8835     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8836     { WM_INITMENU, sent|defwinproc },
8837     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8838     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
8839     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
8840 
8841     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
8842 
8843     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8844     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
8845     { WM_CAPTURECHANGED, sent|defwinproc },
8846     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
8847     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8848     { WM_EXITMENULOOP, sent|defwinproc },
8849     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8850     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8851     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8852     { 0 }
8853 };
8854 static const struct message WmShiftMouseButton[] = {
8855     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
8856     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
8857     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
8858     { WM_MOUSEMOVE, wparam|optional, 0, 0 },
8859     { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
8860     { WM_LBUTTONDOWN, wparam, MK_LBUTTON|MK_SHIFT, 0 },
8861     { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON|MK_SHIFT, 0 },
8862     { WM_LBUTTONUP, wparam, MK_SHIFT, 0 },
8863     { WM_LBUTTONUP, sent|wparam, MK_SHIFT, 0 },
8864     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
8865     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
8866     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
8867     { 0 }
8868 };
8869 static const struct message WmF1Seq[] = {
8870     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
8871     { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
8872     { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
8873     { WM_KEYF1, wparam|lparam, 0, 0 },
8874     { WM_KEYF1, sent|wparam|lparam, 0, 0 },
8875     { WM_HELP, sent|defwinproc },
8876     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
8877     { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
8878     { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
8879     { 0 }
8880 };
8881 static const struct message WmVkAppsSeq[] = {
8882     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
8883     { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
8884     { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
8885     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
8886     { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
8887     { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
8888     { WM_CONTEXTMENU, lparam, /*hwnd*/0, -1 },
8889     { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, -1 },
8890     { 0 }
8891 };
8892 static const struct message WmVkF10Seq[] = {
8893     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
8894     { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
8895     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
8896     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
8897     { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
8898     { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
8899     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
8900     { HCBT_SYSCOMMAND, hook },
8901     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8902     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8903     { WM_INITMENU, sent|defwinproc },
8904     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8905     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
8906     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
8907 
8908     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0x10000001 }, /* XP */
8909 
8910     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
8911     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8912     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
8913     { WM_CAPTURECHANGED, sent|defwinproc },
8914     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
8915     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8916     { WM_EXITMENULOOP, sent|defwinproc },
8917     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
8918     { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
8919     { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
8920     { 0 }
8921 };
8922 static const struct message WmShiftF10Seq[] = {
8923     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
8924     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
8925     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x00000001 },
8926     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
8927     { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
8928     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
8929     { WM_CONTEXTMENU, sent|defwinproc|lparam, /*hwnd*/0, -1 },
8930     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
8931     { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
8932     { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
8933     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
8934     { HCBT_SYSCOMMAND, hook },
8935     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8936     { WM_INITMENU, sent|defwinproc },
8937     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
8938     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xd0000001 }, /* XP */
8939     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0x10000001 }, /* XP */
8940     { WM_CAPTURECHANGED, sent|defwinproc|wparam|lparam, 0, 0 },
8941     { WM_MENUSELECT, sent|defwinproc|wparam|lparam, 0xffff0000, 0 },
8942     { WM_EXITMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8943     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 }, /* XP */
8944     { WM_KEYUP, wparam|lparam, VK_ESCAPE, 0xc0000001 },
8945     { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
8946     { 0 }
8947 };
8948 
8949 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
8950 {
8951     MSG msg;
8952 
8953     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
8954     {
8955         struct recvd_message log_msg;
8956 
8957         /* ignore some unwanted messages */
8958         if (msg.message == WM_MOUSEMOVE ||
8959             msg.message == WM_TIMER ||
8960             ignore_message( msg.message ))
8961             continue;
8962 
8963         log_msg.hwnd = msg.hwnd;
8964         log_msg.message = msg.message;
8965         log_msg.flags = wparam|lparam;
8966         log_msg.wParam = msg.wParam;
8967         log_msg.lParam = msg.lParam;
8968         log_msg.descr = "accel";
8969         add_message(&log_msg);
8970 
8971         if (!hAccel || !TranslateAcceleratorA(hwnd, hAccel, &msg))
8972         {
8973             TranslateMessage(&msg);
8974             DispatchMessageA(&msg);
8975         }
8976     }
8977 }
8978 
8979 static void test_accelerators(void)
8980 {
8981     RECT rc;
8982     POINT pt;
8983     SHORT state;
8984     HACCEL hAccel;
8985     HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8986                                 100, 100, 200, 200, 0, 0, 0, NULL);
8987     BOOL ret;
8988 
8989     assert(hwnd != 0);
8990     UpdateWindow(hwnd);
8991     flush_events();
8992     flush_sequence();
8993 
8994     SetFocus(hwnd);
8995     ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
8996 
8997     state = GetKeyState(VK_SHIFT);
8998     ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
8999     state = GetKeyState(VK_CAPITAL);
9000     ok(state == 0, "wrong CapsLock state %04x\n", state);
9001 
9002     hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
9003     assert(hAccel != 0);
9004 
9005     flush_events();
9006     pump_msg_loop(hwnd, 0);
9007     flush_sequence();
9008 
9009     trace("testing VK_N press/release\n");
9010     flush_sequence();
9011     keybd_event('N', 0, 0, 0);
9012     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9013     pump_msg_loop(hwnd, hAccel);
9014     if (!sequence_cnt)  /* we didn't get any message */
9015     {
9016         skip( "queuing key events not supported\n" );
9017         goto done;
9018     }
9019     ok_sequence(WmVkN, "VK_N press/release", FALSE);
9020 
9021     trace("testing Shift+VK_N press/release\n");
9022     flush_sequence();
9023     keybd_event(VK_SHIFT, 0, 0, 0);
9024     keybd_event('N', 0, 0, 0);
9025     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9026     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9027     pump_msg_loop(hwnd, hAccel);
9028     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
9029 
9030     trace("testing Ctrl+VK_N press/release\n");
9031     flush_sequence();
9032     keybd_event(VK_CONTROL, 0, 0, 0);
9033     keybd_event('N', 0, 0, 0);
9034     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9035     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9036     pump_msg_loop(hwnd, hAccel);
9037     ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
9038 
9039     trace("testing Alt+VK_N press/release\n");
9040     flush_sequence();
9041     keybd_event(VK_MENU, 0, 0, 0);
9042     keybd_event('N', 0, 0, 0);
9043     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9044     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9045     pump_msg_loop(hwnd, hAccel);
9046     ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
9047 
9048     trace("testing Ctrl+Alt+VK_N press/release 1\n");
9049     flush_sequence();
9050     keybd_event(VK_CONTROL, 0, 0, 0);
9051     keybd_event(VK_MENU, 0, 0, 0);
9052     keybd_event('N', 0, 0, 0);
9053     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9054     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9055     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9056     pump_msg_loop(hwnd, hAccel);
9057     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
9058 
9059     ret = DestroyAcceleratorTable(hAccel);
9060     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
9061 
9062     hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(2));
9063     assert(hAccel != 0);
9064 
9065     trace("testing VK_N press/release\n");
9066     flush_sequence();
9067     keybd_event('N', 0, 0, 0);
9068     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9069     pump_msg_loop(hwnd, hAccel);
9070     ok_sequence(WmVkN, "VK_N press/release", FALSE);
9071 
9072     trace("testing Shift+VK_N press/release\n");
9073     flush_sequence();
9074     keybd_event(VK_SHIFT, 0, 0, 0);
9075     keybd_event('N', 0, 0, 0);
9076     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9077     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9078     pump_msg_loop(hwnd, hAccel);
9079     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
9080 
9081     trace("testing Ctrl+VK_N press/release 2\n");
9082     flush_sequence();
9083     keybd_event(VK_CONTROL, 0, 0, 0);
9084     keybd_event('N', 0, 0, 0);
9085     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9086     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9087     pump_msg_loop(hwnd, hAccel);
9088     ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
9089 
9090     trace("testing Alt+VK_N press/release 2\n");
9091     flush_sequence();
9092     keybd_event(VK_MENU, 0, 0, 0);
9093     keybd_event('N', 0, 0, 0);
9094     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9095     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9096     pump_msg_loop(hwnd, hAccel);
9097     ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
9098 
9099     trace("testing Ctrl+Alt+VK_N press/release 2\n");
9100     flush_sequence();
9101     keybd_event(VK_CONTROL, 0, 0, 0);
9102     keybd_event(VK_MENU, 0, 0, 0);
9103     keybd_event('N', 0, 0, 0);
9104     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9105     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9106     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9107     pump_msg_loop(hwnd, hAccel);
9108     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
9109 
9110     trace("testing Ctrl+Shift+VK_N press/release\n");
9111     flush_sequence();
9112     keybd_event(VK_CONTROL, 0, 0, 0);
9113     keybd_event(VK_SHIFT, 0, 0, 0);
9114     keybd_event('N', 0, 0, 0);
9115     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9116     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9117     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9118     pump_msg_loop(hwnd, hAccel);
9119     ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
9120 
9121     trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
9122     flush_sequence();
9123     keybd_event(VK_CONTROL, 0, 0, 0);
9124     keybd_event(VK_MENU, 0, 0, 0);
9125     keybd_event(VK_SHIFT, 0, 0, 0);
9126     keybd_event('N', 0, 0, 0);
9127     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9128     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9129     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9130     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9131     pump_msg_loop(hwnd, hAccel);
9132     ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
9133 
9134     ret = DestroyAcceleratorTable(hAccel);
9135     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
9136     hAccel = 0;
9137 
9138     trace("testing Alt press/release\n");
9139     flush_sequence();
9140     keybd_event(VK_MENU, 0, 0, 0);
9141     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9142     keybd_event(VK_MENU, 0, 0, 0);
9143     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9144     pump_msg_loop(hwnd, 0);
9145     /* this test doesn't pass in Wine for managed windows */
9146     ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
9147 
9148     trace("testing VK_F1 press/release\n");
9149     keybd_event(VK_F1, 0, 0, 0);
9150     keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
9151     pump_msg_loop(hwnd, 0);
9152     ok_sequence(WmF1Seq, "F1 press/release", FALSE);
9153 
9154     trace("testing VK_APPS press/release\n");
9155     keybd_event(VK_APPS, 0, 0, 0);
9156     keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
9157     pump_msg_loop(hwnd, 0);
9158     ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
9159 
9160     trace("testing VK_F10 press/release\n");
9161     keybd_event(VK_F10, 0, 0, 0);
9162     keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
9163     keybd_event(VK_F10, 0, 0, 0);
9164     keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
9165     pump_msg_loop(hwnd, 0);
9166     ok_sequence(WmVkF10Seq, "VK_F10 press/release", TRUE);
9167 
9168     trace("testing SHIFT+F10 press/release\n");
9169     keybd_event(VK_SHIFT, 0, 0, 0);
9170     keybd_event(VK_F10, 0, 0, 0);
9171     keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
9172     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9173     keybd_event(VK_ESCAPE, 0, 0, 0);
9174     keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
9175     pump_msg_loop(hwnd, 0);
9176     ok_sequence(WmShiftF10Seq, "SHIFT+F10 press/release", TRUE);
9177 
9178     trace("testing Shift+MouseButton press/release\n");
9179     /* first, move mouse pointer inside of the window client area */
9180     GetClientRect(hwnd, &rc);
9181     MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
9182     rc.left += (rc.right - rc.left)/2;
9183     rc.top += (rc.bottom - rc.top)/2;
9184     SetCursorPos(rc.left, rc.top);
9185     SetActiveWindow(hwnd);
9186 
9187     flush_events();
9188     flush_sequence();
9189     GetCursorPos(&pt);
9190     if (pt.x == rc.left && pt.y == rc.top)
9191     {
9192         int i;
9193         keybd_event(VK_SHIFT, 0, 0, 0);
9194         mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
9195         mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
9196         keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9197         pump_msg_loop(hwnd, 0);
9198         for (i = 0; i < sequence_cnt; i++) if (sequence[i].message == WM_LBUTTONDOWN) break;
9199         if (i < sequence_cnt)
9200             ok_sequence(WmShiftMouseButton, "Shift+MouseButton press/release", FALSE);
9201         else
9202             skip( "Shift+MouseButton event didn't get to the window\n" );
9203     }
9204 
9205 done:
9206     if (hAccel) DestroyAcceleratorTable(hAccel);
9207     DestroyWindow(hwnd);
9208 }
9209 
9210 /************* window procedures ********************/
9211 
9212 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message,
9213 			     WPARAM wParam, LPARAM lParam)
9214 {
9215     static LONG defwndproc_counter = 0;
9216     static LONG beginpaint_counter = 0;
9217     LRESULT ret;
9218     struct recvd_message msg;
9219 
9220     if (ignore_message( message )) return 0;
9221 
9222     switch (message)
9223     {
9224 	case WM_ENABLE:
9225 	{
9226 	    LONG style = GetWindowLongA(hwnd, GWL_STYLE);
9227 	    ok((BOOL)wParam == !(style & WS_DISABLED),
9228 		"wrong WS_DISABLED state: %ld != %d\n", wParam, !(style & WS_DISABLED));
9229 	    break;
9230 	}
9231 
9232 	case WM_CAPTURECHANGED:
9233 	    if (test_DestroyWindow_flag)
9234 	    {
9235 		DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
9236 		if (style & WS_CHILD)
9237 		    lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
9238 		else if (style & WS_POPUP)
9239 		    lParam = WND_POPUP_ID;
9240 		else
9241 		    lParam = WND_PARENT_ID;
9242 	    }
9243 	    break;
9244 
9245 	case WM_NCDESTROY:
9246 	{
9247 	    HWND capture;
9248 
9249 	    ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
9250 	    capture = GetCapture();
9251 	    if (capture)
9252 	    {
9253 		ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
9254 		trace("current capture %p, releasing...\n", capture);
9255 		ReleaseCapture();
9256 	    }
9257 	}
9258 	/* fall through */
9259 	case WM_DESTROY:
9260             if (pGetAncestor)
9261 	        ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
9262 	    if (test_DestroyWindow_flag)
9263 	    {
9264 		DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
9265 		if (style & WS_CHILD)
9266 		    lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
9267 		else if (style & WS_POPUP)
9268 		    lParam = WND_POPUP_ID;
9269 		else
9270 		    lParam = WND_PARENT_ID;
9271 	    }
9272 	    break;
9273 
9274 	/* test_accelerators() depends on this */
9275 	case WM_NCHITTEST:
9276 	    return HTCLIENT;
9277 
9278 	case WM_USER+10:
9279 	{
9280 	    ACTIVATION_CONTEXT_BASIC_INFORMATION basicinfo;
9281 	    HANDLE handle, event = (HANDLE)lParam;
9282 	    BOOL ret;
9283 
9284 	    handle = (void*)0xdeadbeef;
9285 	    ret = pGetCurrentActCtx(&handle);
9286 	    ok(ret, "failed to get current context, %u\n", GetLastError());
9287 	    ok(handle == 0, "got active context %p\n", handle);
9288 
9289 	    memset(&basicinfo, 0xff, sizeof(basicinfo));
9290 	    ret = pQueryActCtxW(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX, handle, 0, ActivationContextBasicInformation,
9291 	        &basicinfo, sizeof(basicinfo), NULL);
9292 	    ok(ret, "got %d, error %d\n", ret, GetLastError());
9293 	    ok(basicinfo.hActCtx == NULL, "got %p\n", basicinfo.hActCtx);
9294 	    ok(basicinfo.dwFlags == 0, "got %x\n", basicinfo.dwFlags);
9295 
9296 	    if (event) SetEvent(event);
9297 	    return 1;
9298 	}
9299 
9300 	/* ignore */
9301 	case WM_MOUSEMOVE:
9302 	case WM_MOUSEACTIVATE:
9303 	case WM_NCMOUSEMOVE:
9304 	case WM_SETCURSOR:
9305 	case WM_IME_SELECT:
9306 	    return 0;
9307     }
9308 
9309     msg.hwnd = hwnd;
9310     msg.message = message;
9311     msg.flags = sent|wparam|lparam;
9312     if (defwndproc_counter) msg.flags |= defwinproc;
9313     if (beginpaint_counter) msg.flags |= beginpaint;
9314     msg.wParam = wParam;
9315     msg.lParam = lParam;
9316     msg.descr = "MsgCheckProc";
9317     add_message(&msg);
9318 
9319     if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
9320     {
9321 	HWND parent = GetParent(hwnd);
9322 	RECT rc;
9323 	MINMAXINFO *minmax = (MINMAXINFO *)lParam;
9324 
9325 	GetClientRect(parent, &rc);
9326 	trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
9327         trace("Reserved=%d,%d MaxSize=%d,%d MaxPos=%d,%d MinTrack=%d,%d MaxTrack=%d,%d\n",
9328               minmax->ptReserved.x, minmax->ptReserved.y,
9329               minmax->ptMaxSize.x, minmax->ptMaxSize.y,
9330               minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
9331               minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
9332               minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
9333 
9334 	ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n",
9335 	   minmax->ptMaxSize.x, rc.right);
9336 	ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %d != %d\n",
9337 	   minmax->ptMaxSize.y, rc.bottom);
9338     }
9339 
9340     if (message == WM_PAINT)
9341     {
9342         PAINTSTRUCT ps;
9343         beginpaint_counter++;
9344         BeginPaint( hwnd, &ps );
9345         beginpaint_counter--;
9346         EndPaint( hwnd, &ps );
9347         return 0;
9348     }
9349 
9350     if (message == WM_CONTEXTMENU)
9351     {
9352         /* don't create context menu */
9353         return 0;
9354     }
9355 
9356     defwndproc_counter++;
9357     ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam)
9358 		  : DefWindowProcA(hwnd, message, wParam, lParam);
9359     defwndproc_counter--;
9360 
9361     return ret;
9362 }
9363 
9364 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9365 {
9366     return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
9367 }
9368 
9369 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9370 {
9371     return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
9372 }
9373 
9374 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9375 {
9376     static LONG defwndproc_counter = 0;
9377     LRESULT ret;
9378     struct recvd_message msg;
9379 
9380     if (ignore_message( message )) return 0;
9381 
9382     switch (message)
9383     {
9384     case WM_QUERYENDSESSION:
9385     case WM_ENDSESSION:
9386         lParam &= ~0x01;  /* Vista adds a 0x01 flag */
9387         break;
9388     }
9389 
9390     msg.hwnd = hwnd;
9391     msg.message = message;
9392     msg.flags = sent|wparam|lparam;
9393     if (defwndproc_counter) msg.flags |= defwinproc;
9394     msg.wParam = wParam;
9395     msg.lParam = lParam;
9396     msg.descr = "popup";
9397     add_message(&msg);
9398 
9399     if (message == WM_CREATE)
9400     {
9401 	DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
9402 	SetWindowLongA(hwnd, GWL_STYLE, style);
9403     }
9404 
9405     defwndproc_counter++;
9406     ret = DefWindowProcA(hwnd, message, wParam, lParam);
9407     defwndproc_counter--;
9408 
9409     return ret;
9410 }
9411 
9412 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9413 {
9414     static LONG defwndproc_counter = 0;
9415     static LONG beginpaint_counter = 0;
9416     LRESULT ret;
9417     struct recvd_message msg;
9418 
9419     if (ignore_message( message )) return 0;
9420 
9421     if (log_all_parent_messages ||
9422         message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
9423 	message == WM_SETFOCUS || message == WM_KILLFOCUS ||
9424 	message == WM_ENABLE ||	message == WM_ENTERIDLE ||
9425 	message == WM_DRAWITEM || message == WM_MEASUREITEM || message == WM_COMPAREITEM ||
9426 	message == WM_COMMAND || message == WM_IME_SETCONTEXT)
9427     {
9428         switch (message)
9429         {
9430             /* ignore */
9431             case WM_NCHITTEST:
9432                 return HTCLIENT;
9433             case WM_SETCURSOR:
9434             case WM_MOUSEMOVE:
9435             case WM_NCMOUSEMOVE:
9436                 return 0;
9437 
9438             case WM_ERASEBKGND:
9439             {
9440                 RECT rc;
9441                 INT ret = GetClipBox((HDC)wParam, &rc);
9442 
9443                 trace("WM_ERASEBKGND: GetClipBox()=%d, %s\n", ret, wine_dbgstr_rect(&rc));
9444                 break;
9445             }
9446         }
9447 
9448         msg.hwnd = hwnd;
9449         msg.message = message;
9450         msg.flags = sent|parent|wparam|lparam;
9451         if (defwndproc_counter) msg.flags |= defwinproc;
9452         if (beginpaint_counter) msg.flags |= beginpaint;
9453         msg.wParam = wParam;
9454         msg.lParam = lParam;
9455         msg.descr = "parent";
9456         add_message(&msg);
9457     }
9458 
9459     if (message == WM_PAINT)
9460     {
9461         PAINTSTRUCT ps;
9462         beginpaint_counter++;
9463         BeginPaint( hwnd, &ps );
9464         beginpaint_counter--;
9465         EndPaint( hwnd, &ps );
9466         return 0;
9467     }
9468 
9469     defwndproc_counter++;
9470     ret = DefWindowProcA(hwnd, message, wParam, lParam);
9471     defwndproc_counter--;
9472 
9473     return message == WM_COMPAREITEM ? -1 : ret;
9474 }
9475 
9476 static INT_PTR CALLBACK StopQuitMsgCheckProcA(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
9477 {
9478     if (message == WM_CREATE)
9479         PostMessageA(hwnd, WM_CLOSE, 0, 0);
9480     else if (message == WM_CLOSE)
9481     {
9482         /* Only the first WM_QUIT will survive the window destruction */
9483         PostMessageA(hwnd, WM_USER, 0x1234, 0x5678);
9484         PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
9485         PostMessageA(hwnd, WM_QUIT, 0x4321, 0x8765);
9486     }
9487 
9488     return DefWindowProcA(hwnd, message, wp, lp);
9489 }
9490 
9491 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9492 {
9493     static LONG defwndproc_counter = 0;
9494     LRESULT ret;
9495     struct recvd_message msg;
9496 
9497     if (ignore_message( message )) return 0;
9498 
9499     if (test_def_id)
9500     {
9501         DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
9502         ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
9503         if (after_end_dialog)
9504             ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
9505         else
9506             ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
9507     }
9508 
9509     msg.hwnd = hwnd;
9510     msg.message = message;
9511     msg.flags = sent|wparam|lparam;
9512     if (defwndproc_counter) msg.flags |= defwinproc;
9513     msg.wParam = wParam;
9514     msg.lParam = lParam;
9515     msg.descr = "dialog";
9516     add_message(&msg);
9517 
9518     defwndproc_counter++;
9519     ret = DefDlgProcA(hwnd, message, wParam, lParam);
9520     defwndproc_counter--;
9521 
9522     return ret;
9523 }
9524 
9525 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9526 {
9527     static LONG defwndproc_counter = 0;
9528     LRESULT ret;
9529     struct recvd_message msg;
9530 
9531     /* log only specific messages we are interested in */
9532     switch (message)
9533     {
9534 #if 0 /* probably log these as well */
9535     case WM_ACTIVATE:
9536     case WM_SETFOCUS:
9537     case WM_KILLFOCUS:
9538 #endif
9539     case WM_SHOWWINDOW:
9540     case WM_SIZE:
9541     case WM_MOVE:
9542     case WM_GETMINMAXINFO:
9543     case WM_WINDOWPOSCHANGING:
9544     case WM_WINDOWPOSCHANGED:
9545         break;
9546 
9547     default: /* ignore */
9548         /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
9549         return DefWindowProcA(hwnd, message, wParam, lParam);
9550     }
9551 
9552     msg.hwnd = hwnd;
9553     msg.message = message;
9554     msg.flags = sent|wparam|lparam;
9555     if (defwndproc_counter) msg.flags |= defwinproc;
9556     msg.wParam = wParam;
9557     msg.lParam = lParam;
9558     msg.descr = "show";
9559     add_message(&msg);
9560 
9561     defwndproc_counter++;
9562     ret = DefWindowProcA(hwnd, message, wParam, lParam);
9563     defwndproc_counter--;
9564 
9565     return ret;
9566 }
9567 
9568 static LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
9569 {
9570     switch (msg)
9571     {
9572         case WM_CREATE: return 0;
9573         case WM_PAINT:
9574         {
9575             MSG msg2;
9576             static int i = 0;
9577 
9578             if (i < 256)
9579             {
9580                 i++;
9581                 if (PeekMessageA(&msg2, 0, 0, 0, 1))
9582                 {
9583                     TranslateMessage(&msg2);
9584                     DispatchMessageA(&msg2);
9585                 }
9586                 i--;
9587             }
9588             else ok(broken(1), "infinite loop\n");
9589             if ( i == 0)
9590                 paint_loop_done = TRUE;
9591             return DefWindowProcA(hWnd,msg,wParam,lParam);
9592         }
9593     }
9594     return DefWindowProcA(hWnd,msg,wParam,lParam);
9595 }
9596 
9597 static LRESULT WINAPI HotkeyMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9598 {
9599     static LONG defwndproc_counter = 0;
9600     LRESULT ret;
9601     struct recvd_message msg;
9602     DWORD queue_status;
9603 
9604     if (ignore_message( message )) return 0;
9605 
9606     if ((message >= WM_KEYFIRST && message <= WM_KEYLAST) ||
9607         message == WM_HOTKEY || message >= WM_APP)
9608     {
9609         msg.hwnd = hwnd;
9610         msg.message = message;
9611         msg.flags = sent|wparam|lparam;
9612         if (defwndproc_counter) msg.flags |= defwinproc;
9613         msg.wParam = wParam;
9614         msg.lParam = lParam;
9615         msg.descr = "HotkeyMsgCheckProcA";
9616         add_message(&msg);
9617     }
9618 
9619     defwndproc_counter++;
9620     ret = DefWindowProcA(hwnd, message, wParam, lParam);
9621     defwndproc_counter--;
9622 
9623     if (message == WM_APP)
9624     {
9625         queue_status = GetQueueStatus(QS_HOTKEY);
9626         ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
9627         queue_status = GetQueueStatus(QS_POSTMESSAGE);
9628         ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
9629         PostMessageA(hwnd, WM_APP+1, 0, 0);
9630     }
9631     else if (message == WM_APP+1)
9632     {
9633         queue_status = GetQueueStatus(QS_HOTKEY);
9634         ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
9635     }
9636 
9637     return ret;
9638 }
9639 
9640 static BOOL RegisterWindowClasses(void)
9641 {
9642     WNDCLASSA cls;
9643     WNDCLASSW clsW;
9644 
9645     cls.style = 0;
9646     cls.lpfnWndProc = MsgCheckProcA;
9647     cls.cbClsExtra = 0;
9648     cls.cbWndExtra = 0;
9649     cls.hInstance = GetModuleHandleA(0);
9650     cls.hIcon = 0;
9651     cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
9652     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
9653     cls.lpszMenuName = NULL;
9654     cls.lpszClassName = "TestWindowClass";
9655     if(!RegisterClassA(&cls)) return FALSE;
9656 
9657     cls.lpfnWndProc = HotkeyMsgCheckProcA;
9658     cls.lpszClassName = "HotkeyWindowClass";
9659     if(!RegisterClassA(&cls)) return FALSE;
9660 
9661     cls.lpfnWndProc = ShowWindowProcA;
9662     cls.lpszClassName = "ShowWindowClass";
9663     if(!RegisterClassA(&cls)) return FALSE;
9664 
9665     cls.lpfnWndProc = PopupMsgCheckProcA;
9666     cls.lpszClassName = "TestPopupClass";
9667     if(!RegisterClassA(&cls)) return FALSE;
9668 
9669     cls.lpfnWndProc = ParentMsgCheckProcA;
9670     cls.lpszClassName = "TestParentClass";
9671     if(!RegisterClassA(&cls)) return FALSE;
9672 
9673     cls.lpfnWndProc = StopQuitMsgCheckProcA;
9674     cls.lpszClassName = "StopQuitClass";
9675     if(!RegisterClassA(&cls)) return FALSE;
9676 
9677     cls.lpfnWndProc = DefWindowProcA;
9678     cls.lpszClassName = "SimpleWindowClass";
9679     if(!RegisterClassA(&cls)) return FALSE;
9680 
9681     cls.lpfnWndProc = PaintLoopProcA;
9682     cls.lpszClassName = "PaintLoopWindowClass";
9683     if(!RegisterClassA(&cls)) return FALSE;
9684 
9685     cls.style = CS_NOCLOSE;
9686     cls.lpszClassName = "NoCloseWindowClass";
9687     if(!RegisterClassA(&cls)) return FALSE;
9688 
9689     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
9690     cls.style = 0;
9691     cls.hInstance = GetModuleHandleA(0);
9692     cls.hbrBackground = 0;
9693     cls.lpfnWndProc = TestDlgProcA;
9694     cls.lpszClassName = "TestDialogClass";
9695     if(!RegisterClassA(&cls)) return FALSE;
9696 
9697     clsW.style = 0;
9698     clsW.lpfnWndProc = MsgCheckProcW;
9699     clsW.cbClsExtra = 0;
9700     clsW.cbWndExtra = 0;
9701     clsW.hInstance = GetModuleHandleW(0);
9702     clsW.hIcon = 0;
9703     clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
9704     clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
9705     clsW.lpszMenuName = NULL;
9706     clsW.lpszClassName = testWindowClassW;
9707     RegisterClassW(&clsW);  /* ignore error, this fails on Win9x */
9708 
9709     return TRUE;
9710 }
9711 
9712 static BOOL is_our_logged_class(HWND hwnd)
9713 {
9714     char buf[256];
9715 
9716     if (GetClassNameA(hwnd, buf, sizeof(buf)))
9717     {
9718 	if (!lstrcmpiA(buf, "TestWindowClass") ||
9719 	    !lstrcmpiA(buf, "ShowWindowClass") ||
9720 	    !lstrcmpiA(buf, "TestParentClass") ||
9721 	    !lstrcmpiA(buf, "TestPopupClass") ||
9722 	    !lstrcmpiA(buf, "SimpleWindowClass") ||
9723 	    !lstrcmpiA(buf, "TestDialogClass") ||
9724 	    !lstrcmpiA(buf, "MDI_frame_class") ||
9725 	    !lstrcmpiA(buf, "MDI_client_class") ||
9726 	    !lstrcmpiA(buf, "MDI_child_class") ||
9727 	    !lstrcmpiA(buf, "my_button_class") ||
9728 	    !lstrcmpiA(buf, "my_edit_class") ||
9729 	    !lstrcmpiA(buf, "static") ||
9730 	    !lstrcmpiA(buf, "ListBox") ||
9731 	    !lstrcmpiA(buf, "ComboBox") ||
9732 	    !lstrcmpiA(buf, "MyDialogClass") ||
9733 	    !lstrcmpiA(buf, "#32770") ||
9734 	    !lstrcmpiA(buf, "#32768"))
9735         return TRUE;
9736     }
9737     return FALSE;
9738 }
9739 
9740 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
9741 {
9742     HWND hwnd;
9743 
9744     ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
9745 
9746     if (nCode == HCBT_CLICKSKIPPED)
9747     {
9748         /* ignore this event, XP sends it a lot when switching focus between windows */
9749 	return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
9750     }
9751 
9752     if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
9753     {
9754 	struct recvd_message msg;
9755 
9756         msg.hwnd = 0;
9757 	msg.message = nCode;
9758 	msg.flags = hook|wparam|lparam;
9759 	msg.wParam = wParam;
9760 	msg.lParam = lParam;
9761         msg.descr = "CBT";
9762 	add_message(&msg);
9763 
9764 	return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
9765     }
9766 
9767     if (nCode == HCBT_DESTROYWND)
9768     {
9769 	if (test_DestroyWindow_flag)
9770 	{
9771 	    DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
9772 	    if (style & WS_CHILD)
9773 		lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
9774 	    else if (style & WS_POPUP)
9775 		lParam = WND_POPUP_ID;
9776 	    else
9777 		lParam = WND_PARENT_ID;
9778 	}
9779     }
9780 
9781     /* Log also SetFocus(0) calls */
9782     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
9783 
9784     if (is_our_logged_class(hwnd))
9785     {
9786         struct recvd_message msg;
9787 
9788         msg.hwnd = hwnd;
9789         msg.message = nCode;
9790         msg.flags = hook|wparam|lparam;
9791         msg.wParam = wParam;
9792         msg.lParam = lParam;
9793         msg.descr = "CBT";
9794         add_message(&msg);
9795     }
9796     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
9797 }
9798 
9799 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
9800 				    DWORD event,
9801 				    HWND hwnd,
9802 				    LONG object_id,
9803 				    LONG child_id,
9804 				    DWORD thread_id,
9805 				    DWORD event_time)
9806 {
9807     ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
9808 
9809     /* ignore mouse cursor events */
9810     if (object_id == OBJID_CURSOR) return;
9811 
9812     if (!hwnd || is_our_logged_class(hwnd))
9813     {
9814         struct recvd_message msg;
9815 
9816         msg.hwnd = hwnd;
9817         msg.message = event;
9818         msg.flags = winevent_hook|wparam|lparam;
9819         msg.wParam = object_id;
9820         msg.lParam = child_id;
9821         msg.descr = "WEH";
9822         add_message(&msg);
9823     }
9824 }
9825 
9826 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
9827 static const WCHAR wszAnsi[] = {'U',0};
9828 
9829 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
9830 {
9831     switch (uMsg)
9832     {
9833     case CB_FINDSTRINGEXACT:
9834         trace("String: %p\n", (LPCWSTR)lParam);
9835         if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
9836             return 1;
9837         if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
9838             return 0;
9839         return -1;
9840     }
9841     return DefWindowProcW(hwnd, uMsg, wParam, lParam);
9842 }
9843 
9844 static const struct message WmGetTextLengthAfromW[] = {
9845     { WM_GETTEXTLENGTH, sent },
9846     { WM_GETTEXT, sent|optional },
9847     { 0 }
9848 };
9849 
9850 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
9851 
9852 /* dummy window proc for WM_GETTEXTLENGTH test */
9853 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
9854 {
9855     switch(msg)
9856     {
9857     case WM_GETTEXTLENGTH:
9858         return lstrlenW(dummy_window_text) + 37;  /* some random length */
9859     case WM_GETTEXT:
9860         lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
9861         return lstrlenW( (LPWSTR)lp );
9862     default:
9863         return DefWindowProcW( hwnd, msg, wp, lp );
9864     }
9865 }
9866 
9867 static void test_message_conversion(void)
9868 {
9869     static const WCHAR wszMsgConversionClass[] =
9870         {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
9871     WNDCLASSW cls;
9872     LRESULT lRes;
9873     HWND hwnd;
9874     WNDPROC wndproc, newproc;
9875     BOOL ret;
9876 
9877     cls.style = 0;
9878     cls.lpfnWndProc = MsgConversionProcW;
9879     cls.cbClsExtra = 0;
9880     cls.cbWndExtra = 0;
9881     cls.hInstance = GetModuleHandleW(NULL);
9882     cls.hIcon = NULL;
9883     cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
9884     cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
9885     cls.lpszMenuName = NULL;
9886     cls.lpszClassName = wszMsgConversionClass;
9887     /* this call will fail on Win9x, but that doesn't matter as this test is
9888      * meaningless on those platforms */
9889     if(!RegisterClassW(&cls)) return;
9890 
9891     hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
9892                            100, 100, 200, 200, 0, 0, 0, NULL);
9893     ok(hwnd != NULL, "Window creation failed\n");
9894 
9895     /* {W, A} -> A */
9896 
9897     wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
9898     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9899     ok(lRes == 0, "String should have been converted\n");
9900     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9901     ok(lRes == 1, "String shouldn't have been converted\n");
9902 
9903     /* {W, A} -> W */
9904 
9905     wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
9906     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9907     ok(lRes == 1, "String shouldn't have been converted\n");
9908     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9909     ok(lRes == 1, "String shouldn't have been converted\n");
9910 
9911     /* Synchronous messages */
9912 
9913     lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9914     ok(lRes == 0, "String should have been converted\n");
9915     lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9916     ok(lRes == 1, "String shouldn't have been converted\n");
9917 
9918     /* Asynchronous messages */
9919 
9920     SetLastError(0);
9921     lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9922     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9923         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9924     SetLastError(0);
9925     lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9926     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9927         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9928     SetLastError(0);
9929     lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9930     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9931         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9932     SetLastError(0);
9933     lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9934     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9935         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9936     SetLastError(0);
9937     lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9938     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9939         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9940     SetLastError(0);
9941     lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9942     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9943         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9944     SetLastError(0);
9945     lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
9946     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9947         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9948     SetLastError(0);
9949     lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
9950     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9951         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9952 
9953     /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
9954 
9955     hwnd = CreateWindowW (testWindowClassW, wszUnicode,
9956                           WS_OVERLAPPEDWINDOW,
9957                           100, 100, 200, 200, 0, 0, 0, NULL);
9958     assert(hwnd);
9959     flush_sequence();
9960     lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
9961     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
9962     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
9963         "got bad length %ld\n", lRes );
9964 
9965     flush_sequence();
9966     lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
9967                             hwnd, WM_GETTEXTLENGTH, 0, 0);
9968     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
9969     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
9970         "got bad length %ld\n", lRes );
9971 
9972     wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
9973     newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
9974     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
9975     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
9976                                      NULL, 0, NULL, NULL ) ||
9977         broken(lRes == lstrlenW(dummy_window_text) + 37),
9978         "got bad length %ld\n", lRes );
9979 
9980     SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc );  /* restore old wnd proc */
9981     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
9982     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
9983                                      NULL, 0, NULL, NULL ) ||
9984         broken(lRes == lstrlenW(dummy_window_text) + 37),
9985         "got bad length %ld\n", lRes );
9986 
9987     ret = DestroyWindow(hwnd);
9988     ok( ret, "DestroyWindow() error %d\n", GetLastError());
9989 }
9990 
9991 struct timer_info
9992 {
9993     HWND hWnd;
9994     HANDLE handles[2];
9995     DWORD id;
9996 };
9997 
9998 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
9999 {
10000 }
10001 
10002 #define TIMER_ID               0x19
10003 #define TIMER_COUNT_EXPECTED   100
10004 #define TIMER_COUNT_TOLERANCE  10
10005 
10006 static int count = 0;
10007 static void CALLBACK callback_count(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
10008 {
10009     count++;
10010 }
10011 
10012 static DWORD exception;
10013 static void CALLBACK callback_exception(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
10014 {
10015     count++;
10016     RaiseException(exception, 0, 0, NULL);
10017 }
10018 
10019 static DWORD WINAPI timer_thread_proc(LPVOID x)
10020 {
10021     struct timer_info *info = x;
10022     DWORD r;
10023 
10024     r = KillTimer(info->hWnd, 0x19);
10025     ok(r,"KillTimer failed in thread\n");
10026     r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
10027     ok(r,"SetTimer failed in thread\n");
10028     ok(r==TIMER_ID,"SetTimer id different\n");
10029     r = SetEvent(info->handles[0]);
10030     ok(r,"SetEvent failed in thread\n");
10031     return 0;
10032 }
10033 
10034 static void test_timers(void)
10035 {
10036     struct timer_info info;
10037     DWORD start;
10038     DWORD id;
10039     MSG msg;
10040 
10041     info.hWnd = CreateWindowA("TestWindowClass", NULL,
10042        WS_OVERLAPPEDWINDOW ,
10043        CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
10044        NULL, NULL, 0);
10045 
10046     info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
10047     ok(info.id, "SetTimer failed\n");
10048     ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
10049     info.handles[0] = CreateEventW(NULL,0,0,NULL);
10050     info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
10051 
10052     WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
10053 
10054     WaitForSingleObject(info.handles[1], INFINITE);
10055 
10056     CloseHandle(info.handles[0]);
10057     CloseHandle(info.handles[1]);
10058 
10059     ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
10060 
10061     /* Check the minimum allowed timeout for a timer.  MSDN indicates that it should be 10.0 ms,
10062      * which occurs sometimes, but most testing on the VMs indicates a minimum timeout closer to
10063      * 15.6 ms.  Since there is some measurement error between test runs we are allowing for
10064      * ±9 counts (~4 ms) around the expected value.
10065      */
10066     count = 0;
10067     id = SetTimer(info.hWnd, TIMER_ID, 0, callback_count);
10068     ok(id != 0, "did not get id from SetTimer.\n");
10069     ok(id==TIMER_ID, "SetTimer timer ID different\n");
10070     start = GetTickCount();
10071     while (GetTickCount()-start < 1001 && GetMessageA(&msg, info.hWnd, 0, 0))
10072         DispatchMessageA(&msg);
10073 todo_wine
10074     ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE /* xp */
10075        || broken(abs(count-64) < TIMER_COUNT_TOLERANCE) /* most common */
10076        || broken(abs(count-43) < TIMER_COUNT_TOLERANCE) /* w2k3, win8 */,
10077        "did not get expected count for minimum timeout (%d != ~%d).\n",
10078        count, TIMER_COUNT_EXPECTED);
10079     ok(KillTimer(info.hWnd, id), "KillTimer failed\n");
10080     /* Perform the same check on SetSystemTimer (only available on w2k3 and older) */
10081     if (pSetSystemTimer)
10082     {
10083         int syscount = 0;
10084 
10085         count = 0;
10086         id = pSetSystemTimer(info.hWnd, TIMER_ID, 0, callback_count);
10087         ok(id != 0, "did not get id from SetSystemTimer.\n");
10088         ok(id==TIMER_ID, "SetTimer timer ID different\n");
10089         start = GetTickCount();
10090         while (GetTickCount()-start < 1001 && GetMessageA(&msg, info.hWnd, 0, 0))
10091         {
10092             if (msg.message == WM_SYSTIMER)
10093                 syscount++;
10094             DispatchMessageA(&msg);
10095         }
10096         ok(abs(syscount-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE
10097            || broken(abs(syscount-64) < TIMER_COUNT_TOLERANCE) /* most common */
10098            || broken(syscount > 4000 && syscount < 12000) /* win2k3sp0 */,
10099            "did not get expected count for minimum timeout (%d != ~%d).\n",
10100            syscount, TIMER_COUNT_EXPECTED);
10101         todo_wine ok(count == 0, "did not get expected count for callback timeout (%d != 0).\n",
10102                                  count);
10103         ok(pKillSystemTimer(info.hWnd, id), "KillSystemTimer failed\n");
10104     }
10105 
10106     ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
10107 }
10108 
10109 static void test_timers_no_wnd(void)
10110 {
10111     static UINT_PTR ids[0xffff];
10112     UINT_PTR id, id2;
10113     DWORD start;
10114     MSG msg;
10115     int i;
10116 
10117     count = 0;
10118     id = SetTimer(NULL, 0, 100, callback_count);
10119     ok(id != 0, "did not get id from SetTimer.\n");
10120     id2 = SetTimer(NULL, id, 200, callback_count);
10121     ok(id2 == id, "did not get same id from SetTimer when replacing (%li expected %li).\n", id2, id);
10122     Sleep(150);
10123     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
10124     ok(count == 0, "did not get zero count as expected (%i).\n", count);
10125     Sleep(150);
10126     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
10127     ok(count == 1, "did not get one count as expected (%i).\n", count);
10128     KillTimer(NULL, id);
10129     Sleep(250);
10130     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
10131     ok(count == 1, "killing replaced timer did not work (%i).\n", count);
10132 
10133     /* Check the minimum allowed timeout for a timer.  MSDN indicates that it should be 10.0 ms,
10134      * which occurs sometimes, but most testing on the VMs indicates a minimum timeout closer to
10135      * 15.6 ms.  Since there is some measurement error between test runs we are allowing for
10136      * ±9 counts (~4 ms) around the expected value.
10137      */
10138     count = 0;
10139     id = SetTimer(NULL, 0, 0, callback_count);
10140     ok(id != 0, "did not get id from SetTimer.\n");
10141     start = GetTickCount();
10142     while (GetTickCount()-start < 1001 && GetMessageA(&msg, NULL, 0, 0))
10143         DispatchMessageA(&msg);
10144 todo_wine
10145     ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE /* xp */
10146        || broken(abs(count-64) < TIMER_COUNT_TOLERANCE) /* most common */,
10147        "did not get expected count for minimum timeout (%d != ~%d).\n",
10148        count, TIMER_COUNT_EXPECTED);
10149     KillTimer(NULL, id);
10150     /* Note: SetSystemTimer doesn't support a NULL window, see test_timers */
10151 
10152     if (pSetCoalescableTimer)
10153     {
10154         count = 0;
10155         id = pSetCoalescableTimer(NULL, 0, 0, callback_count, 0);
10156         ok(id != 0, "SetCoalescableTimer failed with %u.\n", GetLastError());
10157         start = GetTickCount();
10158         while (GetTickCount()-start < 100 && GetMessageA(&msg, NULL, 0, 0))
10159             DispatchMessageA(&msg);
10160         ok(count > 1, "expected count > 1, got %d.\n", count);
10161         KillTimer(NULL, id);
10162     }
10163     else
10164         win_skip("SetCoalescableTimer not available.\n");
10165 
10166     /* Check what happens when we're running out of timers */
10167     for (i=0; i<sizeof(ids)/sizeof(ids[0]); i++)
10168     {
10169         SetLastError(0xdeadbeef);
10170         ids[i] = SetTimer(NULL, 0, USER_TIMER_MAXIMUM, tfunc);
10171         if (!ids[i]) break;
10172     }
10173     ok(i != sizeof(ids)/sizeof(ids[0]), "all timers were created successfully\n");
10174     ok(GetLastError()==ERROR_NO_MORE_USER_HANDLES || broken(GetLastError()==0xdeadbeef),
10175             "GetLastError() = %d\n", GetLastError());
10176     while (i > 0) KillTimer(NULL, ids[--i]);
10177 }
10178 
10179 static void test_timers_exception(DWORD code)
10180 {
10181     UINT_PTR id;
10182     MSG msg;
10183 
10184     exception = code;
10185     id = SetTimer(NULL, 0, 1000, callback_exception);
10186     ok(id != 0, "did not get id from SetTimer.\n");
10187 
10188     memset(&msg, 0, sizeof(msg));
10189     msg.message = WM_TIMER;
10190     msg.wParam = id;
10191     msg.lParam = (LPARAM)callback_exception;
10192 
10193     count = 0;
10194     DispatchMessageA(&msg);
10195     ok(count == 1, "did not get one count as expected (%i).\n", count);
10196 
10197     KillTimer(NULL, id);
10198 }
10199 
10200 static void test_timers_exceptions(void)
10201 {
10202     test_timers_exception(EXCEPTION_ACCESS_VIOLATION);
10203     test_timers_exception(EXCEPTION_DATATYPE_MISALIGNMENT);
10204     test_timers_exception(EXCEPTION_BREAKPOINT);
10205     test_timers_exception(EXCEPTION_SINGLE_STEP);
10206     test_timers_exception(EXCEPTION_ARRAY_BOUNDS_EXCEEDED);
10207     test_timers_exception(EXCEPTION_FLT_DENORMAL_OPERAND);
10208     test_timers_exception(EXCEPTION_FLT_DIVIDE_BY_ZERO);
10209     test_timers_exception(EXCEPTION_FLT_INEXACT_RESULT);
10210     test_timers_exception(EXCEPTION_ILLEGAL_INSTRUCTION);
10211     test_timers_exception(0xE000BEEF); /* customer exception */
10212 }
10213 
10214 /* Various win events with arbitrary parameters */
10215 static const struct message WmWinEventsSeq[] = {
10216     { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
10217     { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
10218     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
10219     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
10220     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
10221     { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
10222     { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
10223     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
10224     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
10225     /* our win event hook ignores OBJID_CURSOR events */
10226     /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
10227     { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
10228     { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
10229     { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
10230     { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
10231     { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
10232     { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
10233     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
10234     { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
10235     { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
10236     { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
10237     { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
10238     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
10239     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
10240     { 0 }
10241 };
10242 static const struct message WmWinEventCaretSeq[] = {
10243     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
10244     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
10245     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
10246     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
10247     { 0 }
10248 };
10249 static const struct message WmWinEventCaretSeq_2[] = {
10250     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
10251     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
10252     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
10253     { 0 }
10254 };
10255 static const struct message WmWinEventAlertSeq[] = {
10256     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
10257     { 0 }
10258 };
10259 static const struct message WmWinEventAlertSeq_2[] = {
10260     /* create window in the thread proc */
10261     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
10262     /* our test event */
10263     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
10264     { 0 }
10265 };
10266 static const struct message WmGlobalHookSeq_1[] = {
10267     /* create window in the thread proc */
10268     { HCBT_CREATEWND, hook|lparam, 0, 2 },
10269     /* our test events */
10270     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
10271     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
10272     { 0 }
10273 };
10274 static const struct message WmGlobalHookSeq_2[] = {
10275     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
10276     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
10277     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
10278     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
10279     { 0 }
10280 };
10281 
10282 static const struct message WmMouseLLHookSeq[] = {
10283     { WM_MOUSEMOVE, hook },
10284     { WM_LBUTTONUP, hook },
10285     { WM_MOUSEMOVE, hook },
10286     { 0 }
10287 };
10288 
10289 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
10290 					 DWORD event,
10291 					 HWND hwnd,
10292 					 LONG object_id,
10293 					 LONG child_id,
10294 					 DWORD thread_id,
10295 					 DWORD event_time)
10296 {
10297     char buf[256];
10298 
10299     if (GetClassNameA(hwnd, buf, sizeof(buf)))
10300     {
10301 	if (!lstrcmpiA(buf, "TestWindowClass") ||
10302 	    !lstrcmpiA(buf, "static"))
10303 	{
10304 	    struct recvd_message msg;
10305 
10306             msg.hwnd = hwnd;
10307 	    msg.message = event;
10308 	    msg.flags = winevent_hook|wparam|lparam;
10309 	    msg.wParam = object_id;
10310 	    msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
10311             msg.descr = "WEH_2";
10312 	    add_message(&msg);
10313 	}
10314     }
10315 }
10316 
10317 static HHOOK hCBT_global_hook;
10318 static DWORD cbt_global_hook_thread_id;
10319 
10320 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
10321 {
10322     HWND hwnd;
10323     char buf[256];
10324 
10325     if (nCode == HCBT_SYSCOMMAND)
10326     {
10327 	struct recvd_message msg;
10328 
10329         msg.hwnd = 0;
10330 	msg.message = nCode;
10331 	msg.flags = hook|wparam|lparam;
10332 	msg.wParam = wParam;
10333 	msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
10334         msg.descr = "CBT_2";
10335 	add_message(&msg);
10336 
10337 	return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
10338     }
10339     /* WH_MOUSE_LL hook */
10340     if (nCode == HC_ACTION)
10341     {
10342         MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
10343 
10344         /* we can't test for real mouse events */
10345         if (mhll->flags & LLMHF_INJECTED)
10346         {
10347 	    struct recvd_message msg;
10348 
10349 	    memset (&msg, 0, sizeof (msg));
10350 	    msg.message = wParam;
10351 	    msg.flags = hook;
10352             msg.descr = "CBT_2";
10353 	    add_message(&msg);
10354         }
10355 	return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
10356     }
10357 
10358     /* Log also SetFocus(0) calls */
10359     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
10360 
10361     if (GetClassNameA(hwnd, buf, sizeof(buf)))
10362     {
10363 	if (!lstrcmpiA(buf, "TestWindowClass") ||
10364 	    !lstrcmpiA(buf, "static"))
10365 	{
10366 	    struct recvd_message msg;
10367 
10368             msg.hwnd = hwnd;
10369 	    msg.message = nCode;
10370 	    msg.flags = hook|wparam|lparam;
10371 	    msg.wParam = wParam;
10372 	    msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
10373             msg.descr = "CBT_2";
10374 	    add_message(&msg);
10375 	}
10376     }
10377     return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
10378 }
10379 
10380 static DWORD WINAPI win_event_global_thread_proc(void *param)
10381 {
10382     HWND hwnd;
10383     MSG msg;
10384     HANDLE hevent = *(HANDLE *)param;
10385 
10386     assert(pNotifyWinEvent);
10387 
10388     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
10389     assert(hwnd);
10390     trace("created thread window %p\n", hwnd);
10391 
10392     *(HWND *)param = hwnd;
10393 
10394     flush_sequence();
10395     /* this event should be received only by our new hook proc,
10396      * an old one does not expect an event from another thread.
10397      */
10398     pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
10399     SetEvent(hevent);
10400 
10401     while (GetMessageA(&msg, 0, 0, 0))
10402     {
10403 	TranslateMessage(&msg);
10404 	DispatchMessageA(&msg);
10405     }
10406     return 0;
10407 }
10408 
10409 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
10410 {
10411     HWND hwnd;
10412     MSG msg;
10413     HANDLE hevent = *(HANDLE *)param;
10414 
10415     flush_sequence();
10416     /* these events should be received only by our new hook proc,
10417      * an old one does not expect an event from another thread.
10418      */
10419 
10420     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
10421     assert(hwnd);
10422     trace("created thread window %p\n", hwnd);
10423 
10424     *(HWND *)param = hwnd;
10425 
10426     /* Windows doesn't like when a thread plays games with the focus,
10427        that leads to all kinds of misbehaviours and failures to activate
10428        a window. So, better keep next lines commented out.
10429     SetFocus(0);
10430     SetFocus(hwnd);*/
10431 
10432     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
10433     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
10434 
10435     SetEvent(hevent);
10436 
10437     while (GetMessageA(&msg, 0, 0, 0))
10438     {
10439 	TranslateMessage(&msg);
10440 	DispatchMessageA(&msg);
10441     }
10442     return 0;
10443 }
10444 
10445 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
10446 {
10447     HWND hwnd;
10448     MSG msg;
10449     HANDLE hevent = *(HANDLE *)param;
10450 
10451     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
10452     assert(hwnd);
10453     trace("created thread window %p\n", hwnd);
10454 
10455     *(HWND *)param = hwnd;
10456 
10457     flush_sequence();
10458 
10459     /* Windows doesn't like when a thread plays games with the focus,
10460      * that leads to all kinds of misbehaviours and failures to activate
10461      * a window. So, better don't generate a mouse click message below.
10462      */
10463     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10464     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
10465     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10466 
10467     SetEvent(hevent);
10468     while (GetMessageA(&msg, 0, 0, 0))
10469     {
10470         TranslateMessage(&msg);
10471         DispatchMessageA(&msg);
10472     }
10473     return 0;
10474 }
10475 
10476 static void test_winevents(void)
10477 {
10478     BOOL ret;
10479     MSG msg;
10480     HWND hwnd, hwnd2;
10481     UINT i;
10482     HANDLE hthread, hevent;
10483     DWORD tid;
10484     HWINEVENTHOOK hhook;
10485     const struct message *events = WmWinEventsSeq;
10486 
10487     hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
10488 			   WS_OVERLAPPEDWINDOW,
10489 			   CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
10490 			   NULL, NULL, 0);
10491     assert(hwnd);
10492 
10493     /****** start of global hook test *************/
10494     hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
10495     if (!hCBT_global_hook)
10496     {
10497         ok(DestroyWindow(hwnd), "failed to destroy window\n");
10498         skip( "cannot set global hook\n" );
10499         return;
10500     }
10501 
10502     hevent = CreateEventA(NULL, 0, 0, NULL);
10503     assert(hevent);
10504     hwnd2 = hevent;
10505 
10506     hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
10507     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
10508 
10509     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10510 
10511     ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
10512 
10513     flush_sequence();
10514     /* this one should be received only by old hook proc */
10515     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
10516     /* this one should be received only by old hook proc */
10517     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
10518 
10519     ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
10520 
10521     ret = UnhookWindowsHookEx(hCBT_global_hook);
10522     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
10523 
10524     PostThreadMessageA(tid, WM_QUIT, 0, 0);
10525     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10526     CloseHandle(hthread);
10527     CloseHandle(hevent);
10528     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10529     /****** end of global hook test *************/
10530 
10531     if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
10532     {
10533 	ok(DestroyWindow(hwnd), "failed to destroy window\n");
10534 	return;
10535     }
10536 
10537     flush_sequence();
10538 
10539     if (0)
10540     {
10541     /* this test doesn't pass under Win9x */
10542     /* win2k ignores events with hwnd == 0 */
10543     SetLastError(0xdeadbeef);
10544     pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
10545     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
10546        GetLastError() == 0xdeadbeef, /* Win9x */
10547        "unexpected error %d\n", GetLastError());
10548     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
10549     }
10550 
10551     for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++)
10552 	pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
10553 
10554     ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
10555 
10556     /****** start of event filtering test *************/
10557     hhook = pSetWinEventHook(
10558 	EVENT_OBJECT_SHOW, /* 0x8002 */
10559 	EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
10560 	GetModuleHandleA(0), win_event_global_hook_proc,
10561 	GetCurrentProcessId(), 0,
10562 	WINEVENT_INCONTEXT);
10563     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
10564 
10565     hevent = CreateEventA(NULL, 0, 0, NULL);
10566     assert(hevent);
10567     hwnd2 = hevent;
10568 
10569     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
10570     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
10571 
10572     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10573 
10574     ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
10575 
10576     flush_sequence();
10577     /* this one should be received only by old hook proc */
10578     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
10579     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
10580     /* this one should be received only by old hook proc */
10581     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
10582 
10583     ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
10584 
10585     ret = pUnhookWinEvent(hhook);
10586     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10587 
10588     PostThreadMessageA(tid, WM_QUIT, 0, 0);
10589     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10590     CloseHandle(hthread);
10591     CloseHandle(hevent);
10592     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10593     /****** end of event filtering test *************/
10594 
10595     /****** start of out of context event test *************/
10596     hhook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0,
10597         win_event_global_hook_proc, GetCurrentProcessId(), 0,
10598 	WINEVENT_OUTOFCONTEXT);
10599     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
10600 
10601     hevent = CreateEventA(NULL, 0, 0, NULL);
10602     assert(hevent);
10603     hwnd2 = hevent;
10604 
10605     flush_sequence();
10606 
10607     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
10608     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
10609 
10610     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10611 
10612     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
10613     /* process pending winevent messages */
10614     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
10615     ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
10616 
10617     flush_sequence();
10618     /* this one should be received only by old hook proc */
10619     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
10620     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
10621     /* this one should be received only by old hook proc */
10622     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
10623 
10624     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
10625     /* process pending winevent messages */
10626     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
10627     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
10628 
10629     ret = pUnhookWinEvent(hhook);
10630     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10631 
10632     PostThreadMessageA(tid, WM_QUIT, 0, 0);
10633     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10634     CloseHandle(hthread);
10635     CloseHandle(hevent);
10636     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10637     /****** end of out of context event test *************/
10638 
10639     /****** start of MOUSE_LL hook test *************/
10640     hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
10641     /* WH_MOUSE_LL is not supported on Win9x platforms */
10642     if (!hCBT_global_hook)
10643     {
10644         win_skip("Skipping WH_MOUSE_LL test on this platform\n");
10645         goto skip_mouse_ll_hook_test;
10646     }
10647 
10648     hevent = CreateEventA(NULL, 0, 0, NULL);
10649     assert(hevent);
10650     hwnd2 = hevent;
10651 
10652     hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
10653     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
10654 
10655     while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
10656         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
10657 
10658     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
10659     flush_sequence();
10660 
10661     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10662     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
10663     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10664 
10665     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
10666 
10667     ret = UnhookWindowsHookEx(hCBT_global_hook);
10668     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
10669 
10670     PostThreadMessageA(tid, WM_QUIT, 0, 0);
10671     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10672     CloseHandle(hthread);
10673     CloseHandle(hevent);
10674     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10675     /****** end of MOUSE_LL hook test *************/
10676 skip_mouse_ll_hook_test:
10677 
10678     ok(DestroyWindow(hwnd), "failed to destroy window\n");
10679 }
10680 
10681 static void test_set_hook(void)
10682 {
10683     BOOL ret;
10684     HHOOK hhook;
10685     HWINEVENTHOOK hwinevent_hook;
10686 
10687     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
10688     ok(hhook != 0, "local hook does not require hModule set to 0\n");
10689     UnhookWindowsHookEx(hhook);
10690 
10691     if (0)
10692     {
10693     /* this test doesn't pass under Win9x: BUG! */
10694     SetLastError(0xdeadbeef);
10695     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
10696     ok(!hhook, "global hook requires hModule != 0\n");
10697     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
10698     }
10699 
10700     SetLastError(0xdeadbeef);
10701     hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
10702     ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
10703     ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
10704        GetLastError() == 0xdeadbeef, /* Win9x */
10705        "unexpected error %d\n", GetLastError());
10706 
10707     SetLastError(0xdeadbeef);
10708     ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
10709     ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
10710        GetLastError() == 0xdeadbeef, /* Win9x */
10711        "unexpected error %d\n", GetLastError());
10712 
10713     if (!pSetWinEventHook || !pUnhookWinEvent) return;
10714 
10715     /* even process local incontext hooks require hmodule */
10716     SetLastError(0xdeadbeef);
10717     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10718         GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
10719     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
10720     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
10721        GetLastError() == 0xdeadbeef, /* Win9x */
10722        "unexpected error %d\n", GetLastError());
10723 
10724     /* even thread local incontext hooks require hmodule */
10725     SetLastError(0xdeadbeef);
10726     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10727         GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
10728     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
10729     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
10730        GetLastError() == 0xdeadbeef, /* Win9x */
10731        "unexpected error %d\n", GetLastError());
10732 
10733     if (0)
10734     {
10735     /* these 3 tests don't pass under Win9x */
10736     SetLastError(0xdeadbeef);
10737     hwinevent_hook = pSetWinEventHook(1, 0, 0, win_event_proc,
10738         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
10739     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
10740     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
10741 
10742     SetLastError(0xdeadbeef);
10743     hwinevent_hook = pSetWinEventHook(-1, 1, 0, win_event_proc,
10744         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
10745     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
10746     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
10747 
10748     SetLastError(0xdeadbeef);
10749     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10750         0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
10751     ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
10752     ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
10753     }
10754 
10755     SetLastError(0xdeadbeef);
10756     hwinevent_hook = pSetWinEventHook(0, 0, 0, win_event_proc,
10757         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
10758     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
10759     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
10760     ret = pUnhookWinEvent(hwinevent_hook);
10761     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10762 
10763 todo_wine {
10764     /* This call succeeds under win2k SP4, but fails under Wine.
10765        Does win2k test/use passed process id? */
10766     SetLastError(0xdeadbeef);
10767     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10768         0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
10769     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
10770     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
10771     ret = pUnhookWinEvent(hwinevent_hook);
10772     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10773 }
10774 
10775     SetLastError(0xdeadbeef);
10776     ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
10777     ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
10778 	GetLastError() == 0xdeadbeef, /* Win9x */
10779 	"unexpected error %d\n", GetLastError());
10780 }
10781 
10782 static HWND hook_hwnd;
10783 static HHOOK recursive_hook;
10784 static int hook_depth, max_hook_depth;
10785 
10786 static LRESULT WINAPI rec_get_message_hook(int code, WPARAM w, LPARAM l)
10787 {
10788     LRESULT res;
10789     MSG msg;
10790     BOOL b;
10791 
10792     hook_depth++;
10793     if(hook_depth > max_hook_depth)
10794         max_hook_depth = hook_depth;
10795 
10796     b = PeekMessageW(&msg, hook_hwnd, 0, 0, PM_NOREMOVE);
10797     ok(b, "PeekMessage failed\n");
10798 
10799     res = CallNextHookEx(recursive_hook, code, w, l);
10800 
10801     hook_depth--;
10802     return res;
10803 }
10804 
10805 static void test_recursive_hook(void)
10806 {
10807     MSG msg;
10808     BOOL b;
10809 
10810     hook_hwnd = CreateWindowA("Static", NULL, WS_POPUP, 0, 0, 200, 60, NULL, NULL, NULL, NULL);
10811     ok(hook_hwnd != NULL, "CreateWindow failed\n");
10812 
10813     recursive_hook = SetWindowsHookExW(WH_GETMESSAGE, rec_get_message_hook, NULL, GetCurrentThreadId());
10814     ok(recursive_hook != NULL, "SetWindowsHookEx failed\n");
10815 
10816     PostMessageW(hook_hwnd, WM_USER, 0, 0);
10817     PostMessageW(hook_hwnd, WM_USER+1, 0, 0);
10818 
10819     hook_depth = 0;
10820     GetMessageW(&msg, hook_hwnd, 0, 0);
10821     ok(15 <= max_hook_depth && max_hook_depth < 45, "max_hook_depth = %d\n", max_hook_depth);
10822     trace("max_hook_depth = %d\n", max_hook_depth);
10823 
10824     b = UnhookWindowsHookEx(recursive_hook);
10825     ok(b, "UnhokWindowsHookEx failed\n");
10826 
10827     DestroyWindow(hook_hwnd);
10828 }
10829 
10830 static const struct message ScrollWindowPaint1[] = {
10831     { WM_PAINT, sent },
10832     { WM_ERASEBKGND, sent|beginpaint },
10833     { WM_GETTEXTLENGTH, sent|optional },
10834     { WM_PAINT, sent|optional },
10835     { WM_NCPAINT, sent|beginpaint|optional },
10836     { WM_GETTEXT, sent|beginpaint|optional },
10837     { WM_GETTEXT, sent|beginpaint|optional },
10838     { WM_GETTEXT, sent|beginpaint|optional },
10839     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
10840     { WM_ERASEBKGND, sent|beginpaint|optional },
10841     { 0 }
10842 };
10843 
10844 static const struct message ScrollWindowPaint2[] = {
10845     { WM_PAINT, sent },
10846     { 0 }
10847 };
10848 
10849 static void test_scrollwindowex(void)
10850 {
10851     HWND hwnd, hchild;
10852     RECT rect={0,0,130,130};
10853 
10854     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
10855             WS_VISIBLE|WS_OVERLAPPEDWINDOW,
10856             100, 100, 200, 200, 0, 0, 0, NULL);
10857     ok (hwnd != 0, "Failed to create overlapped window\n");
10858     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
10859             WS_VISIBLE|WS_CAPTION|WS_CHILD,
10860             10, 10, 150, 150, hwnd, 0, 0, NULL);
10861     ok (hchild != 0, "Failed to create child\n");
10862     UpdateWindow(hwnd);
10863     flush_events();
10864     flush_sequence();
10865 
10866     /* scroll without the child window */
10867     trace("start scroll\n");
10868     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
10869             SW_ERASE|SW_INVALIDATE);
10870     ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE);
10871     trace("end scroll\n");
10872     flush_sequence();
10873     flush_events();
10874     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE);
10875     flush_events();
10876     flush_sequence();
10877 
10878     /* Now without the SW_ERASE flag */
10879     trace("start scroll\n");
10880     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
10881     ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE);
10882     trace("end scroll\n");
10883     flush_sequence();
10884     flush_events();
10885     ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", FALSE);
10886     flush_events();
10887     flush_sequence();
10888 
10889     /* now scroll the child window as well */
10890     trace("start scroll\n");
10891     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
10892             SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
10893     /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
10894     /* windows sometimes a WM_MOVE */
10895     ok_sequence(WmEmptySeq, "ScrollWindowEx", TRUE);
10896     trace("end scroll\n");
10897     flush_sequence();
10898     flush_events();
10899     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE);
10900     flush_events();
10901     flush_sequence();
10902 
10903     /* now scroll with ScrollWindow() */
10904     trace("start scroll with ScrollWindow\n");
10905     ScrollWindow( hwnd, 5, 5, NULL, NULL);
10906     trace("end scroll\n");
10907     flush_sequence();
10908     flush_events();
10909     ok_sequence(ScrollWindowPaint1, "ScrollWindow", FALSE);
10910 
10911     ok(DestroyWindow(hchild), "failed to destroy window\n");
10912     ok(DestroyWindow(hwnd), "failed to destroy window\n");
10913     flush_sequence();
10914 }
10915 
10916 static const struct message destroy_window_with_children[] = {
10917     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
10918     { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
10919     { 0x0090, sent|optional },
10920     { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
10921     { 0x0090, sent|optional },
10922     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
10923     { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
10924     { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
10925     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
10926     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
10927     { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
10928     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
10929     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
10930     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
10931     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
10932     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
10933     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
10934     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
10935     { 0 }
10936 };
10937 
10938 static void test_DestroyWindow(void)
10939 {
10940     BOOL ret;
10941     HWND parent, child1, child2, child3, child4, test;
10942     UINT_PTR child_id = WND_CHILD_ID + 1;
10943 
10944     parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
10945 			     100, 100, 200, 200, 0, 0, 0, NULL);
10946     assert(parent != 0);
10947     child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
10948 			     0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
10949     assert(child1 != 0);
10950     child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
10951 			     0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
10952     assert(child2 != 0);
10953     child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
10954 			     0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
10955     assert(child3 != 0);
10956     child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
10957 			     0, 0, 50, 50, parent, 0, 0, NULL);
10958     assert(child4 != 0);
10959 
10960     /* test owner/parent of child2 */
10961     test = GetParent(child2);
10962     ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
10963     ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
10964     if(pGetAncestor) {
10965         test = pGetAncestor(child2, GA_PARENT);
10966         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
10967     }
10968     test = GetWindow(child2, GW_OWNER);
10969     ok(!test, "wrong owner %p\n", test);
10970 
10971     test = SetParent(child2, parent);
10972     ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
10973 
10974     /* test owner/parent of the parent */
10975     test = GetParent(parent);
10976     ok(!test, "wrong parent %p\n", test);
10977     ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
10978     if(pGetAncestor) {
10979         test = pGetAncestor(parent, GA_PARENT);
10980         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
10981     }
10982     test = GetWindow(parent, GW_OWNER);
10983     ok(!test, "wrong owner %p\n", test);
10984 
10985     /* test owner/parent of child1 */
10986     test = GetParent(child1);
10987     ok(test == parent, "wrong parent %p\n", test);
10988     ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
10989     if(pGetAncestor) {
10990         test = pGetAncestor(child1, GA_PARENT);
10991         ok(test == parent, "wrong parent %p\n", test);
10992     }
10993     test = GetWindow(child1, GW_OWNER);
10994     ok(!test, "wrong owner %p\n", test);
10995 
10996     /* test owner/parent of child2 */
10997     test = GetParent(child2);
10998     ok(test == parent, "wrong parent %p\n", test);
10999     ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
11000     if(pGetAncestor) {
11001         test = pGetAncestor(child2, GA_PARENT);
11002         ok(test == parent, "wrong parent %p\n", test);
11003     }
11004     test = GetWindow(child2, GW_OWNER);
11005     ok(!test, "wrong owner %p\n", test);
11006 
11007     /* test owner/parent of child3 */
11008     test = GetParent(child3);
11009     ok(test == child1, "wrong parent %p\n", test);
11010     ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
11011     if(pGetAncestor) {
11012         test = pGetAncestor(child3, GA_PARENT);
11013         ok(test == child1, "wrong parent %p\n", test);
11014     }
11015     test = GetWindow(child3, GW_OWNER);
11016     ok(!test, "wrong owner %p\n", test);
11017 
11018     /* test owner/parent of child4 */
11019     test = GetParent(child4);
11020     ok(test == parent, "wrong parent %p\n", test);
11021     ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
11022     if(pGetAncestor) {
11023         test = pGetAncestor(child4, GA_PARENT);
11024         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
11025     }
11026     test = GetWindow(child4, GW_OWNER);
11027     ok(test == parent, "wrong owner %p\n", test);
11028 
11029     flush_sequence();
11030 
11031     trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
11032 	   parent, child1, child2, child3, child4);
11033 
11034     SetCapture(child4);
11035     test = GetCapture();
11036     ok(test == child4, "wrong capture window %p\n", test);
11037 
11038     test_DestroyWindow_flag = TRUE;
11039     ret = DestroyWindow(parent);
11040     ok( ret, "DestroyWindow() error %d\n", GetLastError());
11041     test_DestroyWindow_flag = FALSE;
11042     ok_sequence(destroy_window_with_children, "destroy window with children", FALSE);
11043 
11044     ok(!IsWindow(parent), "parent still exists\n");
11045     ok(!IsWindow(child1), "child1 still exists\n");
11046     ok(!IsWindow(child2), "child2 still exists\n");
11047     ok(!IsWindow(child3), "child3 still exists\n");
11048     ok(!IsWindow(child4), "child4 still exists\n");
11049 
11050     test = GetCapture();
11051     ok(!test, "wrong capture window %p\n", test);
11052 }
11053 
11054 
11055 static const struct message WmDispatchPaint[] = {
11056     { WM_NCPAINT, sent },
11057     { WM_GETTEXT, sent|defwinproc|optional },
11058     { WM_GETTEXT, sent|defwinproc|optional },
11059     { WM_ERASEBKGND, sent },
11060     { 0 }
11061 };
11062 
11063 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11064 {
11065     if (message == WM_PAINT) return 0;
11066     return MsgCheckProcA( hwnd, message, wParam, lParam );
11067 }
11068 
11069 static void test_DispatchMessage(void)
11070 {
11071     RECT rect;
11072     MSG msg;
11073     int count;
11074     HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
11075                                100, 100, 200, 200, 0, 0, 0, NULL);
11076     ShowWindow( hwnd, SW_SHOW );
11077     UpdateWindow( hwnd );
11078     flush_events();
11079     flush_sequence();
11080     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
11081 
11082     SetRect( &rect, -5, -5, 5, 5 );
11083     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
11084     count = 0;
11085     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
11086     {
11087         if (msg.message != WM_PAINT) DispatchMessageA( &msg );
11088         else
11089         {
11090             flush_sequence();
11091             DispatchMessageA( &msg );
11092             /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
11093             if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
11094             else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
11095             if (++count > 10) break;
11096         }
11097     }
11098     ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
11099 
11100     trace("now without DispatchMessage\n");
11101     flush_sequence();
11102     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
11103     count = 0;
11104     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
11105     {
11106         if (msg.message != WM_PAINT) DispatchMessageA( &msg );
11107         else
11108         {
11109             HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
11110             flush_sequence();
11111             /* this will send WM_NCCPAINT just like DispatchMessage does */
11112             GetUpdateRgn( hwnd, hrgn, TRUE );
11113             ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
11114             DeleteObject( hrgn );
11115             GetClientRect( hwnd, &rect );
11116             ValidateRect( hwnd, &rect );  /* this will stop WM_PAINTs */
11117             ok( !count, "Got multiple WM_PAINTs\n" );
11118             if (++count > 10) break;
11119         }
11120     }
11121 
11122     flush_sequence();
11123     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
11124     count = 0;
11125     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
11126     {
11127         if (msg.message != WM_PAINT) DispatchMessageA( &msg );
11128         else
11129         {
11130             HDC hdc;
11131 
11132             flush_sequence();
11133             hdc = BeginPaint( hwnd, NULL );
11134             ok( !hdc, "got valid hdc %p from BeginPaint\n", hdc );
11135             ok( !EndPaint( hwnd, NULL ), "EndPaint succeeded\n" );
11136             ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
11137             ok( !count, "Got multiple WM_PAINTs\n" );
11138             if (++count > 10) break;
11139         }
11140     }
11141     DestroyWindow(hwnd);
11142 }
11143 
11144 
11145 static const struct message WmUser[] = {
11146     { WM_USER, sent },
11147     { 0 }
11148 };
11149 
11150 struct sendmsg_info
11151 {
11152     HWND  hwnd;
11153     DWORD timeout;
11154     DWORD ret;
11155 };
11156 
11157 static DWORD CALLBACK send_msg_thread( LPVOID arg )
11158 {
11159     struct sendmsg_info *info = arg;
11160     SetLastError( 0xdeadbeef );
11161     info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
11162     if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT ||
11163                         broken(GetLastError() == 0),  /* win9x */
11164                         "unexpected error %d\n", GetLastError());
11165     return 0;
11166 }
11167 
11168 static void wait_for_thread( HANDLE thread )
11169 {
11170     while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
11171     {
11172         MSG msg;
11173         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA(&msg);
11174     }
11175 }
11176 
11177 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11178 {
11179     if (message == WM_USER) Sleep(200);
11180     return MsgCheckProcA( hwnd, message, wParam, lParam );
11181 }
11182 
11183 static void test_SendMessageTimeout(void)
11184 {
11185     HANDLE thread;
11186     struct sendmsg_info info;
11187     DWORD tid;
11188     BOOL is_win9x;
11189 
11190     info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
11191                                100, 100, 200, 200, 0, 0, 0, NULL);
11192     flush_events();
11193     flush_sequence();
11194 
11195     info.timeout = 1000;
11196     info.ret = 0xdeadbeef;
11197     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11198     wait_for_thread( thread );
11199     CloseHandle( thread );
11200     ok( info.ret == 1, "SendMessageTimeout failed\n" );
11201     ok_sequence( WmUser, "WmUser", FALSE );
11202 
11203     info.timeout = 1;
11204     info.ret = 0xdeadbeef;
11205     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11206     Sleep(100);  /* SendMessageTimeout should time out here */
11207     wait_for_thread( thread );
11208     CloseHandle( thread );
11209     ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
11210     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
11211 
11212     /* 0 means infinite timeout (but not on win9x) */
11213     info.timeout = 0;
11214     info.ret = 0xdeadbeef;
11215     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11216     Sleep(100);
11217     wait_for_thread( thread );
11218     CloseHandle( thread );
11219     is_win9x = !info.ret;
11220     if (is_win9x) ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
11221     else ok_sequence( WmUser, "WmUser", FALSE );
11222 
11223     /* timeout is treated as signed despite the prototype (but not on win9x) */
11224     info.timeout = 0x7fffffff;
11225     info.ret = 0xdeadbeef;
11226     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11227     Sleep(100);
11228     wait_for_thread( thread );
11229     CloseHandle( thread );
11230     ok( info.ret == 1, "SendMessageTimeout failed\n" );
11231     ok_sequence( WmUser, "WmUser", FALSE );
11232 
11233     info.timeout = 0x80000000;
11234     info.ret = 0xdeadbeef;
11235     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11236     Sleep(100);
11237     wait_for_thread( thread );
11238     CloseHandle( thread );
11239     if (is_win9x)
11240     {
11241         ok( info.ret == 1, "SendMessageTimeout failed\n" );
11242         ok_sequence( WmUser, "WmUser", FALSE );
11243     }
11244     else
11245     {
11246         ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
11247         ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
11248     }
11249 
11250     /* now check for timeout during message processing */
11251     SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
11252     info.timeout = 100;
11253     info.ret = 0xdeadbeef;
11254     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11255     wait_for_thread( thread );
11256     CloseHandle( thread );
11257     /* we should time out but still get the message */
11258     ok( info.ret == 0, "SendMessageTimeout failed\n" );
11259     ok_sequence( WmUser, "WmUser", FALSE );
11260 
11261     DestroyWindow( info.hwnd );
11262 }
11263 
11264 
11265 /****************** edit message test *************************/
11266 #define ID_EDIT 0x1234
11267 static const struct message sl_edit_setfocus[] =
11268 {
11269     { HCBT_SETFOCUS, hook },
11270     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11271     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11272     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11273     { WM_SETFOCUS, sent|wparam, 0 },
11274     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11275     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 },
11276     { WM_CTLCOLOREDIT, sent|parent },
11277     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11278     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11279     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11280     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11281     { 0 }
11282 };
11283 static const struct message sl_edit_invisible[] =
11284 {
11285     { HCBT_SETFOCUS, hook },
11286     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11287     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11288     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11289     { WM_KILLFOCUS, sent|parent },
11290     { WM_SETFOCUS, sent },
11291     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11292     { 0 }
11293 };
11294 static const struct message ml_edit_setfocus[] =
11295 {
11296     { HCBT_SETFOCUS, hook },
11297     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11298     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11299     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11300     { WM_SETFOCUS, sent|wparam, 0 },
11301     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11302     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11303     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11304     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11305     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11306     { 0 }
11307 };
11308 static const struct message sl_edit_killfocus[] =
11309 {
11310     { HCBT_SETFOCUS, hook },
11311     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11312     { WM_KILLFOCUS, sent|wparam, 0 },
11313     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11314     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11315     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
11316     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
11317     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
11318     { 0 }
11319 };
11320 static const struct message sl_edit_lbutton_dblclk[] =
11321 {
11322     { WM_LBUTTONDBLCLK, sent },
11323     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11324     { 0 }
11325 };
11326 static const struct message sl_edit_lbutton_down[] =
11327 {
11328     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
11329     { HCBT_SETFOCUS, hook },
11330     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11331     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11332     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11333     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
11334     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11335     { WM_CTLCOLOREDIT, sent|parent },
11336     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11337     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11338     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11339     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11340     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11341     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11342     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11343     { WM_CTLCOLOREDIT, sent|parent|optional },
11344     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11345     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11346     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11347     { 0 }
11348 };
11349 static const struct message ml_edit_lbutton_down[] =
11350 {
11351     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
11352     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11353     { HCBT_SETFOCUS, hook },
11354     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11355     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11356     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11357     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
11358     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11359     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11360     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11361     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11362     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11363     { 0 }
11364 };
11365 static const struct message sl_edit_lbutton_up[] =
11366 {
11367     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
11368     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11369     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
11370     { WM_CAPTURECHANGED, sent|defwinproc },
11371     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11372     { 0 }
11373 };
11374 static const struct message ml_edit_lbutton_up[] =
11375 {
11376     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
11377     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
11378     { WM_CAPTURECHANGED, sent|defwinproc },
11379     { 0 }
11380 };
11381 
11382 static WNDPROC old_edit_proc;
11383 
11384 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11385 {
11386     static LONG defwndproc_counter = 0;
11387     LRESULT ret;
11388     struct recvd_message msg;
11389 
11390     if (ignore_message( message )) return 0;
11391 
11392     msg.hwnd = hwnd;
11393     msg.message = message;
11394     msg.flags = sent|wparam|lparam;
11395     if (defwndproc_counter) msg.flags |= defwinproc;
11396     msg.wParam = wParam;
11397     msg.lParam = lParam;
11398     msg.descr = "edit";
11399     add_message(&msg);
11400 
11401     defwndproc_counter++;
11402     ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
11403     defwndproc_counter--;
11404 
11405     return ret;
11406 }
11407 
11408 static void subclass_edit(void)
11409 {
11410     WNDCLASSA cls;
11411 
11412     if (!GetClassInfoA(0, "edit", &cls)) assert(0);
11413 
11414     old_edit_proc = cls.lpfnWndProc;
11415 
11416     cls.hInstance = GetModuleHandleA(NULL);
11417     cls.lpfnWndProc = edit_hook_proc;
11418     cls.lpszClassName = "my_edit_class";
11419     UnregisterClassA(cls.lpszClassName, cls.hInstance);
11420     if (!RegisterClassA(&cls)) assert(0);
11421 }
11422 
11423 static void test_edit_messages(void)
11424 {
11425     HWND hwnd, parent;
11426     DWORD dlg_code;
11427 
11428     subclass_edit();
11429     log_all_parent_messages++;
11430 
11431     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11432                              100, 100, 200, 200, 0, 0, 0, NULL);
11433     ok (parent != 0, "Failed to create parent window\n");
11434 
11435     /* test single line edit */
11436     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
11437 			   0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
11438     ok(hwnd != 0, "Failed to create edit window\n");
11439 
11440     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
11441     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
11442 
11443     flush_sequence();
11444     SetFocus(hwnd);
11445     ok_sequence(sl_edit_invisible, "SetFocus(hwnd) on an invisible edit", FALSE);
11446 
11447     ShowWindow(hwnd, SW_SHOW);
11448     UpdateWindow(hwnd);
11449     SetFocus(0);
11450     flush_sequence();
11451 
11452     SetFocus(hwnd);
11453     ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
11454 
11455     SetFocus(0);
11456     ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
11457 
11458     SetFocus(0);
11459     ReleaseCapture();
11460     flush_sequence();
11461 
11462     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
11463     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
11464 
11465     SetFocus(0);
11466     ReleaseCapture();
11467     flush_sequence();
11468 
11469     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
11470     ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
11471 
11472     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
11473     ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
11474 
11475     DestroyWindow(hwnd);
11476 
11477     /* test multiline edit */
11478     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
11479 			   0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
11480     ok(hwnd != 0, "Failed to create edit window\n");
11481 
11482     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
11483     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
11484        "wrong dlg_code %08x\n", dlg_code);
11485 
11486     ShowWindow(hwnd, SW_SHOW);
11487     UpdateWindow(hwnd);
11488     SetFocus(0);
11489     flush_sequence();
11490 
11491     SetFocus(hwnd);
11492     ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
11493 
11494     SetFocus(0);
11495     ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
11496 
11497     SetFocus(0);
11498     ReleaseCapture();
11499     flush_sequence();
11500 
11501     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
11502     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
11503 
11504     SetFocus(0);
11505     ReleaseCapture();
11506     flush_sequence();
11507 
11508     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
11509     ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
11510 
11511     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
11512     ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
11513 
11514     DestroyWindow(hwnd);
11515     DestroyWindow(parent);
11516 
11517     log_all_parent_messages--;
11518 }
11519 
11520 /**************************** End of Edit test ******************************/
11521 
11522 static const struct message WmKeyDownSkippedSeq[] =
11523 {
11524     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
11525     { 0 }
11526 };
11527 static const struct message WmKeyDownWasDownSkippedSeq[] =
11528 {
11529     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x40000001 }, /* XP */
11530     { 0 }
11531 };
11532 static const struct message WmKeyUpSkippedSeq[] =
11533 {
11534     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
11535     { 0 }
11536 };
11537 static const struct message WmUserKeyUpSkippedSeq[] =
11538 {
11539     { WM_USER, sent },
11540     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
11541     { 0 }
11542 };
11543 
11544 #define EV_STOP 0
11545 #define EV_SENDMSG 1
11546 #define EV_ACK 2
11547 
11548 struct peekmsg_info
11549 {
11550     HWND  hwnd;
11551     HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
11552 };
11553 
11554 static DWORD CALLBACK send_msg_thread_2(void *param)
11555 {
11556     DWORD ret;
11557     struct peekmsg_info *info = param;
11558 
11559     trace("thread: looping\n");
11560     SetEvent(info->hevent[EV_ACK]);
11561 
11562     while (1)
11563     {
11564         ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
11565 
11566         switch (ret)
11567         {
11568         case WAIT_OBJECT_0 + EV_STOP:
11569             trace("thread: exiting\n");
11570             return 0;
11571 
11572         case WAIT_OBJECT_0 + EV_SENDMSG:
11573             trace("thread: sending message\n");
11574             ret = SendNotifyMessageA(info->hwnd, WM_USER, 0, 0);
11575             ok(ret, "SendNotifyMessageA failed error %u\n", GetLastError());
11576             SetEvent(info->hevent[EV_ACK]);
11577             break;
11578 
11579         default:
11580             trace("unexpected return: %04x\n", ret);
11581             assert(0);
11582             break;
11583         }
11584     }
11585     return 0;
11586 }
11587 
11588 static void test_PeekMessage(void)
11589 {
11590     MSG msg;
11591     HANDLE hthread;
11592     DWORD tid, qstatus;
11593     UINT qs_all_input = QS_ALLINPUT;
11594     UINT qs_input = QS_INPUT;
11595     BOOL ret;
11596     struct peekmsg_info info;
11597 
11598     info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
11599                               100, 100, 200, 200, 0, 0, 0, NULL);
11600     assert(info.hwnd);
11601     ShowWindow(info.hwnd, SW_SHOW);
11602     UpdateWindow(info.hwnd);
11603     SetFocus(info.hwnd);
11604 
11605     info.hevent[EV_STOP] = CreateEventA(NULL, 0, 0, NULL);
11606     info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
11607     info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
11608 
11609     hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
11610     WaitForSingleObject(info.hevent[EV_ACK], 10000);
11611 
11612     flush_events();
11613     flush_sequence();
11614 
11615     SetLastError(0xdeadbeef);
11616     qstatus = GetQueueStatus(qs_all_input);
11617     if (GetLastError() == ERROR_INVALID_FLAGS)
11618     {
11619         trace("QS_RAWINPUT not supported on this platform\n");
11620         qs_all_input &= ~QS_RAWINPUT;
11621         qs_input &= ~QS_RAWINPUT;
11622     }
11623     if (qstatus & QS_POSTMESSAGE)
11624     {
11625         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) /* nothing */ ;
11626         qstatus = GetQueueStatus(qs_all_input);
11627     }
11628     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
11629 
11630     trace("signalling to send message\n");
11631     SetEvent(info.hevent[EV_SENDMSG]);
11632     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11633 
11634     /* pass invalid QS_xxxx flags */
11635     SetLastError(0xdeadbeef);
11636     qstatus = GetQueueStatus(0xffffffff);
11637     ok(qstatus == 0 || broken(qstatus)  /* win9x */, "GetQueueStatus should fail: %08x\n", qstatus);
11638     if (!qstatus)
11639     {
11640         ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
11641         qstatus = GetQueueStatus(qs_all_input);
11642     }
11643     qstatus &= ~MAKELONG( 0x4000, 0x4000 );  /* sometimes set on Win95 */
11644     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
11645        "wrong qstatus %08x\n", qstatus);
11646 
11647     msg.message = 0;
11648     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11649     ok(!ret,
11650        "PeekMessageA should have returned FALSE instead of msg %04x\n",
11651         msg.message);
11652     ok_sequence(WmUser, "WmUser", FALSE);
11653 
11654     qstatus = GetQueueStatus(qs_all_input);
11655     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
11656 
11657     keybd_event('N', 0, 0, 0);
11658     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
11659     qstatus = GetQueueStatus(qs_all_input);
11660     if (!(qstatus & MAKELONG(QS_KEY, QS_KEY)))
11661     {
11662         skip( "queuing key events not supported\n" );
11663         goto done;
11664     }
11665     ok(qstatus == MAKELONG(QS_KEY, QS_KEY) ||
11666        /* keybd_event seems to trigger a sent message on NT4 */
11667        qstatus == MAKELONG(QS_KEY|QS_SENDMESSAGE, QS_KEY|QS_SENDMESSAGE),
11668        "wrong qstatus %08x\n", qstatus);
11669 
11670     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11671     qstatus = GetQueueStatus(qs_all_input);
11672     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY) ||
11673        qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
11674        "wrong qstatus %08x\n", qstatus);
11675 
11676     InvalidateRect(info.hwnd, NULL, FALSE);
11677     qstatus = GetQueueStatus(qs_all_input);
11678     ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY) ||
11679        qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
11680        "wrong qstatus %08x\n", qstatus);
11681 
11682     trace("signalling to send message\n");
11683     SetEvent(info.hevent[EV_SENDMSG]);
11684     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11685 
11686     qstatus = GetQueueStatus(qs_all_input);
11687     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11688        "wrong qstatus %08x\n", qstatus);
11689 
11690     msg.message = 0;
11691     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
11692     if (ret && msg.message == WM_CHAR)
11693     {
11694         win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
11695         goto done;
11696     }
11697     ok(!ret,
11698        "PeekMessageA should have returned FALSE instead of msg %04x\n",
11699         msg.message);
11700     if (!sequence_cnt)  /* nt4 doesn't fetch anything with PM_QS_* flags */
11701     {
11702         win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
11703         goto done;
11704     }
11705     ok_sequence(WmUser, "WmUser", FALSE);
11706 
11707     qstatus = GetQueueStatus(qs_all_input);
11708     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11709        "wrong qstatus %08x\n", qstatus);
11710 
11711     trace("signalling to send message\n");
11712     SetEvent(info.hevent[EV_SENDMSG]);
11713     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11714 
11715     qstatus = GetQueueStatus(qs_all_input);
11716     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11717        "wrong qstatus %08x\n", qstatus);
11718 
11719     msg.message = 0;
11720     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE );
11721     ok(!ret,
11722        "PeekMessageA should have returned FALSE instead of msg %04x\n",
11723         msg.message);
11724     ok_sequence(WmUser, "WmUser", FALSE);
11725 
11726     qstatus = GetQueueStatus(qs_all_input);
11727     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11728        "wrong qstatus %08x\n", qstatus);
11729 
11730     msg.message = 0;
11731     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
11732     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11733        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11734        ret, msg.message, msg.wParam);
11735     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11736 
11737     qstatus = GetQueueStatus(qs_all_input);
11738     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
11739        "wrong qstatus %08x\n", qstatus);
11740 
11741     msg.message = 0;
11742     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
11743     ok(!ret,
11744        "PeekMessageA should have returned FALSE instead of msg %04x\n",
11745         msg.message);
11746     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11747 
11748     qstatus = GetQueueStatus(qs_all_input);
11749     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
11750        "wrong qstatus %08x\n", qstatus);
11751 
11752     msg.message = 0;
11753     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
11754     ok(ret && msg.message == WM_PAINT,
11755        "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
11756     DispatchMessageA(&msg);
11757     ok_sequence(WmPaint, "WmPaint", FALSE);
11758 
11759     qstatus = GetQueueStatus(qs_all_input);
11760     ok(qstatus == MAKELONG(0, QS_KEY),
11761        "wrong qstatus %08x\n", qstatus);
11762 
11763     msg.message = 0;
11764     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
11765     ok(!ret,
11766        "PeekMessageA should have returned FALSE instead of msg %04x\n",
11767         msg.message);
11768     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11769 
11770     qstatus = GetQueueStatus(qs_all_input);
11771     ok(qstatus == MAKELONG(0, QS_KEY),
11772        "wrong qstatus %08x\n", qstatus);
11773 
11774     trace("signalling to send message\n");
11775     SetEvent(info.hevent[EV_SENDMSG]);
11776     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11777 
11778     qstatus = GetQueueStatus(qs_all_input);
11779     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
11780        "wrong qstatus %08x\n", qstatus);
11781 
11782     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11783 
11784     qstatus = GetQueueStatus(qs_all_input);
11785     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
11786        "wrong qstatus %08x\n", qstatus);
11787 
11788     msg.message = 0;
11789     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
11790     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11791        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11792        ret, msg.message, msg.wParam);
11793     ok_sequence(WmUser, "WmUser", FALSE);
11794 
11795     qstatus = GetQueueStatus(qs_all_input);
11796     ok(qstatus == MAKELONG(0, QS_KEY),
11797        "wrong qstatus %08x\n", qstatus);
11798 
11799     msg.message = 0;
11800     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
11801     ok(!ret,
11802        "PeekMessageA should have returned FALSE instead of msg %04x\n",
11803         msg.message);
11804     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11805 
11806     qstatus = GetQueueStatus(qs_all_input);
11807     ok(qstatus == MAKELONG(0, QS_KEY),
11808        "wrong qstatus %08x\n", qstatus);
11809 
11810     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11811 
11812     qstatus = GetQueueStatus(qs_all_input);
11813     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
11814        "wrong qstatus %08x\n", qstatus);
11815 
11816     trace("signalling to send message\n");
11817     SetEvent(info.hevent[EV_SENDMSG]);
11818     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11819 
11820     qstatus = GetQueueStatus(qs_all_input);
11821     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
11822        "wrong qstatus %08x\n", qstatus);
11823 
11824     msg.message = 0;
11825     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
11826     ok(!ret,
11827        "PeekMessageA should have returned FALSE instead of msg %04x\n",
11828         msg.message);
11829     ok_sequence(WmUser, "WmUser", FALSE);
11830 
11831     qstatus = GetQueueStatus(qs_all_input);
11832     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
11833        "wrong qstatus %08x\n", qstatus);
11834 
11835     msg.message = 0;
11836     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
11837         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
11838     else /* workaround for a missing QS_RAWINPUT support */
11839         ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
11840     ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
11841        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
11842        ret, msg.message, msg.wParam);
11843     ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
11844 
11845     qstatus = GetQueueStatus(qs_all_input);
11846     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
11847        "wrong qstatus %08x\n", qstatus);
11848 
11849     msg.message = 0;
11850     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
11851         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
11852     else /* workaround for a missing QS_RAWINPUT support */
11853         ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
11854     ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
11855        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYUP wParam 'N'\n",
11856        ret, msg.message, msg.wParam);
11857     ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
11858 
11859     qstatus = GetQueueStatus(qs_all_input);
11860     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
11861        "wrong qstatus %08x\n", qstatus);
11862 
11863     msg.message = 0;
11864     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
11865     ok(!ret,
11866        "PeekMessageA should have returned FALSE instead of msg %04x\n",
11867         msg.message);
11868     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11869 
11870     qstatus = GetQueueStatus(qs_all_input);
11871     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
11872        "wrong qstatus %08x\n", qstatus);
11873 
11874     msg.message = 0;
11875     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11876     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11877        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11878        ret, msg.message, msg.wParam);
11879     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11880 
11881     qstatus = GetQueueStatus(qs_all_input);
11882     ok(qstatus == 0,
11883        "wrong qstatus %08x\n", qstatus);
11884 
11885     msg.message = 0;
11886     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11887     ok(!ret,
11888        "PeekMessageA should have returned FALSE instead of msg %04x\n",
11889         msg.message);
11890     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11891 
11892     qstatus = GetQueueStatus(qs_all_input);
11893     ok(qstatus == 0,
11894        "wrong qstatus %08x\n", qstatus);
11895 
11896     /* test whether presence of the quit flag in the queue affects
11897      * the queue state
11898      */
11899     PostQuitMessage(0x1234abcd);
11900 
11901     qstatus = GetQueueStatus(qs_all_input);
11902     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
11903        "wrong qstatus %08x\n", qstatus);
11904 
11905     PostMessageA(info.hwnd, WM_USER, 0, 0);
11906 
11907     qstatus = GetQueueStatus(qs_all_input);
11908     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
11909        "wrong qstatus %08x\n", qstatus);
11910 
11911     msg.message = 0;
11912     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11913     ok(ret && msg.message == WM_USER,
11914        "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
11915     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11916 
11917     qstatus = GetQueueStatus(qs_all_input);
11918     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
11919        "wrong qstatus %08x\n", qstatus);
11920 
11921     msg.message = 0;
11922     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11923     ok(ret && msg.message == WM_QUIT,
11924        "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
11925     ok(msg.wParam == 0x1234abcd, "got wParam %08lx instead of 0x1234abcd\n", msg.wParam);
11926     ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
11927     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11928 
11929     qstatus = GetQueueStatus(qs_all_input);
11930 todo_wine {
11931     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
11932        "wrong qstatus %08x\n", qstatus);
11933 }
11934 
11935     msg.message = 0;
11936     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11937     ok(!ret,
11938        "PeekMessageA should have returned FALSE instead of msg %04x\n",
11939         msg.message);
11940     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11941 
11942     qstatus = GetQueueStatus(qs_all_input);
11943     ok(qstatus == 0,
11944        "wrong qstatus %08x\n", qstatus);
11945 
11946     /* some GetMessage tests */
11947 
11948     keybd_event('N', 0, 0, 0);
11949     qstatus = GetQueueStatus(qs_all_input);
11950     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
11951 
11952     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11953     qstatus = GetQueueStatus(qs_all_input);
11954     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
11955 
11956     if (qstatus)
11957     {
11958         ret = GetMessageA( &msg, 0, 0, 0 );
11959         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11960            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11961            ret, msg.message, msg.wParam);
11962         qstatus = GetQueueStatus(qs_all_input);
11963         ok(qstatus == MAKELONG(0, QS_KEY), "wrong qstatus %08x\n", qstatus);
11964     }
11965 
11966     if (qstatus)
11967     {
11968         ret = GetMessageA( &msg, 0, 0, 0 );
11969         ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
11970            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
11971            ret, msg.message, msg.wParam);
11972         ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
11973         qstatus = GetQueueStatus(qs_all_input);
11974         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
11975     }
11976 
11977     keybd_event('N', 0, 0, 0);
11978     qstatus = GetQueueStatus(qs_all_input);
11979     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
11980 
11981     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11982     qstatus = GetQueueStatus(qs_all_input);
11983     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
11984 
11985     if (qstatus & (QS_KEY << 16))
11986     {
11987         ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
11988         ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
11989            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
11990            ret, msg.message, msg.wParam);
11991         ok_sequence(WmKeyDownWasDownSkippedSeq, "WmKeyDownWasDownSkippedSeq", FALSE);
11992         qstatus = GetQueueStatus(qs_all_input);
11993         ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
11994     }
11995 
11996     if (qstatus)
11997     {
11998         ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
11999         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
12000            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
12001            ret, msg.message, msg.wParam);
12002         qstatus = GetQueueStatus(qs_all_input);
12003         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
12004     }
12005 
12006     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
12007     qstatus = GetQueueStatus(qs_all_input);
12008     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
12009 
12010     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
12011     qstatus = GetQueueStatus(qs_all_input);
12012     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
12013 
12014     trace("signalling to send message\n");
12015     SetEvent(info.hevent[EV_SENDMSG]);
12016     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
12017     qstatus = GetQueueStatus(qs_all_input);
12018     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
12019        "wrong qstatus %08x\n", qstatus);
12020 
12021     if (qstatus & (QS_KEY << 16))
12022     {
12023         ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
12024         ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
12025            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
12026            ret, msg.message, msg.wParam);
12027         ok_sequence(WmUserKeyUpSkippedSeq, "WmUserKeyUpSkippedSeq", FALSE);
12028         qstatus = GetQueueStatus(qs_all_input);
12029         ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
12030     }
12031 
12032     if (qstatus)
12033     {
12034         ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
12035         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
12036            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
12037            ret, msg.message, msg.wParam);
12038         qstatus = GetQueueStatus(qs_all_input);
12039         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
12040     }
12041 done:
12042     trace("signalling to exit\n");
12043     SetEvent(info.hevent[EV_STOP]);
12044 
12045     WaitForSingleObject(hthread, INFINITE);
12046 
12047     CloseHandle(hthread);
12048     CloseHandle(info.hevent[0]);
12049     CloseHandle(info.hevent[1]);
12050     CloseHandle(info.hevent[2]);
12051 
12052     DestroyWindow(info.hwnd);
12053 }
12054 
12055 static void wait_move_event(HWND hwnd, int x, int y)
12056 {
12057     MSG msg;
12058     DWORD time;
12059     BOOL ret;
12060 
12061     time = GetTickCount();
12062     while (GetTickCount() - time < 200) {
12063 	ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
12064         if (ret && msg.pt.x > x && msg.pt.y > y) break;
12065         if (!ret) MsgWaitForMultipleObjects( 0, NULL, FALSE, GetTickCount() - time, QS_ALLINPUT );
12066         else Sleep( GetTickCount() - time );
12067     }
12068 }
12069 
12070 #define STEP 5
12071 static void test_PeekMessage2(void)
12072 {
12073     HWND hwnd;
12074     BOOL ret;
12075     MSG msg;
12076     UINT message;
12077     DWORD time1, time2, time3;
12078     int x1, y1, x2, y2, x3, y3;
12079     POINT pos;
12080 
12081     time1 = time2 = time3 = 0;
12082     x1 = y1 = x2 = y2 = x3 = y3 = 0;
12083 
12084     /* Initialise window and make sure it is ready for events */
12085     hwnd = CreateWindowA("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
12086                         10, 10, 800, 800, NULL, NULL, NULL, NULL);
12087     assert(hwnd);
12088     trace("Window for test_PeekMessage2 %p\n", hwnd);
12089     ShowWindow(hwnd, SW_SHOW);
12090     UpdateWindow(hwnd);
12091     SetFocus(hwnd);
12092     GetCursorPos(&pos);
12093     SetCursorPos(100, 100);
12094     mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
12095     flush_events();
12096 
12097     /* Do initial mousemove, wait until we can see it
12098        and then do our test peek with PM_NOREMOVE. */
12099     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
12100     wait_move_event(hwnd, 100-STEP, 100-STEP);
12101 
12102     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
12103     if (!ret)
12104     {
12105         skip( "queuing mouse events not supported\n" );
12106         goto done;
12107     }
12108     else
12109     {
12110 	trace("1st move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
12111 	message = msg.message;
12112 	time1 = msg.time;
12113 	x1 = msg.pt.x;
12114 	y1 = msg.pt.y;
12115         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
12116     }
12117 
12118     /* Allow time to advance a bit, and then simulate the user moving their
12119      * mouse around. After that we peek again with PM_NOREMOVE.
12120      * Although the previous mousemove message was never removed, the
12121      * mousemove we now peek should reflect the recent mouse movements
12122      * because the input queue will merge the move events. */
12123     Sleep(100);
12124     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
12125     wait_move_event(hwnd, x1, y1);
12126 
12127     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
12128     ok(ret, "no message available\n");
12129     if (ret) {
12130 	trace("2nd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
12131 	message = msg.message;
12132 	time2 = msg.time;
12133 	x2 = msg.pt.x;
12134 	y2 = msg.pt.y;
12135         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
12136 	ok(time2 > time1, "message time not advanced: %x %x\n", time1, time2);
12137 	ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
12138     }
12139 
12140     /* Have another go, to drive the point home */
12141     Sleep(100);
12142     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
12143     wait_move_event(hwnd, x2, y2);
12144 
12145     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
12146     ok(ret, "no message available\n");
12147     if (ret) {
12148 	trace("3rd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
12149 	message = msg.message;
12150 	time3 = msg.time;
12151 	x3 = msg.pt.x;
12152 	y3 = msg.pt.y;
12153         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
12154 	ok(time3 > time2, "message time not advanced: %x %x\n", time2, time3);
12155 	ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
12156     }
12157 
12158 done:
12159     DestroyWindow(hwnd);
12160     SetCursorPos(pos.x, pos.y);
12161     flush_events();
12162 }
12163 
12164 static void test_PeekMessage3(void)
12165 {
12166     HWND hwnd;
12167     BOOL ret;
12168     MSG msg;
12169 
12170     hwnd = CreateWindowA("TestWindowClass", "PeekMessage3", WS_OVERLAPPEDWINDOW,
12171                          10, 10, 800, 800, NULL, NULL, NULL, NULL);
12172     ok(hwnd != NULL, "expected hwnd != NULL\n");
12173     flush_events();
12174 
12175     /* GetMessage() and PeekMessage(..., PM_REMOVE) should prefer messages which
12176      * were already seen. */
12177 
12178     SetTimer(hwnd, 1, 0, NULL);
12179     while (!PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE));
12180     ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12181     PostMessageA(hwnd, WM_USER, 0, 0);
12182     ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
12183     ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12184     ret = GetMessageA(&msg, NULL, 0, 0);
12185     ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12186     ret = GetMessageA(&msg, NULL, 0, 0);
12187     ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12188     ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12189     ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12190 
12191     SetTimer(hwnd, 1, 0, NULL);
12192     while (!PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE));
12193     ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12194     PostMessageA(hwnd, WM_USER, 0, 0);
12195     ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12196     ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12197     ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12198     ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12199     ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12200     ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12201 
12202     /* It doesn't matter if a message range is specified or not. */
12203 
12204     SetTimer(hwnd, 1, 0, NULL);
12205     while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12206     ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12207     PostMessageA(hwnd, WM_USER, 0, 0);
12208     ret = GetMessageA(&msg, NULL, 0, 0);
12209     ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12210     ret = GetMessageA(&msg, NULL, 0, 0);
12211     ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12212     ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12213     ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12214 
12215     /* But not if the post messages were added before the PeekMessage() call. */
12216 
12217     PostMessageA(hwnd, WM_USER, 0, 0);
12218     SetTimer(hwnd, 1, 0, NULL);
12219     while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12220     ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12221     ret = GetMessageA(&msg, NULL, 0, 0);
12222     ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12223     ret = GetMessageA(&msg, NULL, 0, 0);
12224     ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12225     ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12226     ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12227 
12228     /* More complicated test with multiple messages. */
12229 
12230     PostMessageA(hwnd, WM_USER, 0, 0);
12231     SetTimer(hwnd, 1, 0, NULL);
12232     while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12233     ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12234     PostMessageA(hwnd, WM_USER + 1, 0, 0);
12235     ret = GetMessageA(&msg, NULL, 0, 0);
12236     ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12237     ret = GetMessageA(&msg, NULL, 0, 0);
12238     ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12239     ret = GetMessageA(&msg, NULL, 0, 0);
12240     ok(ret && msg.message == WM_USER + 1, "msg.message = %u instead of WM_USER + 1\n", msg.message);
12241     ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12242     ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12243 
12244     /* Newer messages are still returned when specifying a message range. */
12245 
12246     SetTimer(hwnd, 1, 0, NULL);
12247     while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12248     ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12249     PostMessageA(hwnd, WM_USER + 1, 0, 0);
12250     PostMessageA(hwnd, WM_USER, 0, 0);
12251     ret = PeekMessageA(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
12252     ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12253     ret = PeekMessageA(&msg, NULL, WM_USER, WM_USER + 1, PM_NOREMOVE);
12254     ok(ret && msg.message == WM_USER + 1, "msg.message = %u instead of WM_USER + 1\n", msg.message);
12255     ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12256     ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12257     ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12258     ok(ret && msg.message == WM_USER + 1, "msg.message = %u instead of WM_USER + 1\n", msg.message);
12259     ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12260     ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12261     ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12262     ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12263 
12264     /* Also works for posted messages, but the situation is a bit different,
12265      * because both messages are in the same queue. */
12266 
12267     PostMessageA(hwnd, WM_TIMER, 0, 0);
12268     while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12269     ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12270     PostMessageA(hwnd, WM_USER, 0, 0);
12271     ret = GetMessageA(&msg, NULL, 0, 0);
12272     ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12273     ret = GetMessageA(&msg, NULL, 0, 0);
12274     ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12275     ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12276     ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12277 
12278     PostMessageA(hwnd, WM_USER, 0, 0);
12279     PostMessageA(hwnd, WM_TIMER, 0, 0);
12280     while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12281     ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12282     ret = GetMessageA(&msg, NULL, 0, 0);
12283     ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12284     ret = GetMessageA(&msg, NULL, 0, 0);
12285     ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12286     ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12287     ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12288 
12289     DestroyWindow(hwnd);
12290     flush_events();
12291 }
12292 
12293 static INT_PTR CALLBACK wm_quit_dlg_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
12294 {
12295     struct recvd_message msg;
12296 
12297     if (ignore_message( message )) return 0;
12298 
12299     msg.hwnd = hwnd;
12300     msg.message = message;
12301     msg.flags = sent|wparam|lparam;
12302     msg.wParam = wp;
12303     msg.lParam = lp;
12304     msg.descr = "dialog";
12305     add_message(&msg);
12306 
12307     switch (message)
12308     {
12309     case WM_INITDIALOG:
12310         PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
12311         PostMessageA(hwnd, WM_USER, 0xdead, 0xbeef);
12312         return 0;
12313 
12314     case WM_GETDLGCODE:
12315         return 0;
12316 
12317     case WM_USER:
12318         EndDialog(hwnd, 0);
12319         break;
12320     }
12321 
12322     return 1;
12323 }
12324 
12325 static const struct message WmQuitDialogSeq[] = {
12326     { HCBT_CREATEWND, hook },
12327     { WM_SETFONT, sent },
12328     { WM_INITDIALOG, sent },
12329     { WM_CHANGEUISTATE, sent|optional },
12330     { HCBT_DESTROYWND, hook },
12331     { 0x0090, sent|optional }, /* Vista */
12332     { WM_DESTROY, sent },
12333     { WM_NCDESTROY, sent },
12334     { 0 }
12335 };
12336 
12337 static const struct message WmStopQuitSeq[] = {
12338     { WM_DWMNCRENDERINGCHANGED, posted|optional },
12339     { WM_CLOSE, posted },
12340     { WM_QUIT, posted|wparam|lparam, 0x1234, 0 },
12341     { 0 }
12342 };
12343 
12344 static void test_quit_message(void)
12345 {
12346     MSG msg;
12347     BOOL ret;
12348 
12349     /* test using PostQuitMessage */
12350     flush_events();
12351     PostQuitMessage(0xbeef);
12352 
12353     msg.message = 0;
12354     ret = PeekMessageA(&msg, 0, 0, 0, PM_QS_SENDMESSAGE);
12355     ok(!ret, "got %x message\n", msg.message);
12356 
12357     ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
12358     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
12359     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12360     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
12361 
12362     ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
12363     ok(ret, "PostMessage failed with error %d\n", GetLastError());
12364 
12365     ret = GetMessageA(&msg, NULL, 0, 0);
12366     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
12367     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
12368 
12369     /* note: WM_QUIT message received after WM_USER message */
12370     ret = GetMessageA(&msg, NULL, 0, 0);
12371     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
12372     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12373     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
12374 
12375     ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12376     ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
12377 
12378     /* now test with PostThreadMessage - different behaviour! */
12379     PostThreadMessageA(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
12380 
12381     ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
12382     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
12383     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12384     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
12385 
12386     ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
12387     ok(ret, "PostMessage failed with error %d\n", GetLastError());
12388 
12389     /* note: we receive the WM_QUIT message first this time */
12390     ret = GetMessageA(&msg, NULL, 0, 0);
12391     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
12392     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12393     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
12394 
12395     ret = GetMessageA(&msg, NULL, 0, 0);
12396     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
12397     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
12398 
12399     flush_events();
12400     flush_sequence();
12401     ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, wm_quit_dlg_proc, 0);
12402     ok(ret == 1, "expected 1, got %d\n", ret);
12403     ok_sequence(WmQuitDialogSeq, "WmQuitDialogSeq", FALSE);
12404     memset(&msg, 0xab, sizeof(msg));
12405     ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12406     ok(ret, "PeekMessage failed\n");
12407     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12408     ok(msg.wParam == 0x1234, "wParam was 0x%lx instead of 0x1234\n", msg.wParam);
12409     ok(msg.lParam == 0, "lParam was 0x%lx instead of 0\n", msg.lParam);
12410 
12411     /* Check what happens to a WM_QUIT message posted to a window that gets
12412      * destroyed.
12413      */
12414     CreateWindowExA(0, "StopQuitClass", "Stop Quit Test", WS_OVERLAPPEDWINDOW,
12415                     0, 0, 100, 100, NULL, NULL, NULL, NULL);
12416     flush_sequence();
12417     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12418     {
12419         struct recvd_message rmsg;
12420         rmsg.hwnd = msg.hwnd;
12421         rmsg.message = msg.message;
12422         rmsg.flags = posted|wparam|lparam;
12423         rmsg.wParam = msg.wParam;
12424         rmsg.lParam = msg.lParam;
12425         rmsg.descr = "stop/quit";
12426         if (msg.message == WM_QUIT)
12427             /* The hwnd can only be checked here */
12428             ok(!msg.hwnd, "The WM_QUIT hwnd was %p instead of NULL\n", msg.hwnd);
12429         add_message(&rmsg);
12430         DispatchMessageA(&msg);
12431     }
12432     ok_sequence(WmStopQuitSeq, "WmStopQuitSeq", FALSE);
12433 }
12434 
12435 static const struct message WmNotifySeq[] = {
12436     { WM_NOTIFY, sent|wparam|lparam, 0x1234, 0xdeadbeef },
12437     { 0 }
12438 };
12439 
12440 static void test_notify_message(void)
12441 {
12442     HWND hwnd;
12443     BOOL ret;
12444     MSG msg;
12445 
12446     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
12447                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0, NULL, NULL, 0);
12448     ok(hwnd != 0, "Failed to create window\n");
12449     flush_events();
12450     flush_sequence();
12451 
12452     ret = SendNotifyMessageA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12453     ok(ret == TRUE, "SendNotifyMessageA failed with error %u\n", GetLastError());
12454     ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12455 
12456     ret = SendNotifyMessageW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12457     ok(ret == TRUE, "SendNotifyMessageW failed with error %u\n", GetLastError());
12458     ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12459 
12460     ret = SendMessageCallbackA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef, NULL, 0);
12461     ok(ret == TRUE, "SendMessageCallbackA failed with error %u\n", GetLastError());
12462     ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12463 
12464     ret = SendMessageCallbackW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef, NULL, 0);
12465     ok(ret == TRUE, "SendMessageCallbackW failed with error %u\n", GetLastError());
12466     ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12467 
12468     ret = PostMessageA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12469     ok(ret == TRUE, "PostMessageA failed with error %u\n", GetLastError());
12470     flush_events();
12471     ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12472 
12473     ret = PostMessageW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12474     ok(ret == TRUE, "PostMessageW failed with error %u\n", GetLastError());
12475     flush_events();
12476     ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12477 
12478     ret = PostThreadMessageA(GetCurrentThreadId(), WM_NOTIFY, 0x1234, 0xdeadbeef);
12479     ok(ret == TRUE, "PostThreadMessageA failed with error %u\n", GetLastError());
12480     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12481     {
12482         msg.hwnd = hwnd;
12483         DispatchMessageA(&msg);
12484     }
12485     ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12486 
12487     ret = PostThreadMessageW(GetCurrentThreadId(), WM_NOTIFY, 0x1234, 0xdeadbeef);
12488     ok(ret == TRUE, "PostThreadMessageW failed with error %u\n", GetLastError());
12489     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12490     {
12491         msg.hwnd = hwnd;
12492         DispatchMessageA(&msg);
12493     }
12494     ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12495 
12496     DestroyWindow(hwnd);
12497 }
12498 
12499 static const struct message WmMouseHoverSeq[] = {
12500     { WM_MOUSEACTIVATE, sent|optional },  /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
12501     { WM_MOUSEACTIVATE, sent|optional },
12502     { WM_TIMER, sent|optional }, /* XP sends it */
12503     { WM_SYSTIMER, sent },
12504     { WM_MOUSEHOVER, sent|wparam, 0 },
12505     { 0 }
12506 };
12507 
12508 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
12509 {
12510     MSG msg;
12511     DWORD start_ticks, end_ticks;
12512 
12513     start_ticks = GetTickCount();
12514     /* add some deviation (50%) to cover not expected delays */
12515     start_ticks += timeout / 2;
12516 
12517     do
12518     {
12519         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12520         {
12521             /* Timer proc messages are not dispatched to the window proc,
12522              * and therefore not logged.
12523              */
12524             if ((msg.message == WM_TIMER || msg.message == WM_SYSTIMER) && msg.hwnd)
12525             {
12526                 struct recvd_message s_msg;
12527 
12528                 s_msg.hwnd = msg.hwnd;
12529                 s_msg.message = msg.message;
12530                 s_msg.flags = sent|wparam|lparam;
12531                 s_msg.wParam = msg.wParam;
12532                 s_msg.lParam = msg.lParam;
12533                 s_msg.descr = "msg_loop";
12534                 add_message(&s_msg);
12535             }
12536             DispatchMessageA(&msg);
12537         }
12538 
12539         end_ticks = GetTickCount();
12540 
12541         /* inject WM_MOUSEMOVE to see how it changes tracking */
12542         if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
12543         {
12544             mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
12545             mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
12546 
12547             inject_mouse_move = FALSE;
12548         }
12549     } while (start_ticks + timeout >= end_ticks);
12550 }
12551 
12552 static void test_TrackMouseEvent(void)
12553 {
12554     TRACKMOUSEEVENT tme;
12555     BOOL ret;
12556     HWND hwnd, hchild;
12557     RECT rc_parent, rc_child;
12558     UINT default_hover_time, hover_width = 0, hover_height = 0;
12559 
12560 #define track_hover(track_hwnd, track_hover_time) \
12561     tme.cbSize = sizeof(tme); \
12562     tme.dwFlags = TME_HOVER; \
12563     tme.hwndTrack = track_hwnd; \
12564     tme.dwHoverTime = track_hover_time; \
12565     SetLastError(0xdeadbeef); \
12566     ret = pTrackMouseEvent(&tme); \
12567     ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
12568 
12569 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
12570     tme.cbSize = sizeof(tme); \
12571     tme.dwFlags = TME_QUERY; \
12572     tme.hwndTrack = (HWND)0xdeadbeef; \
12573     tme.dwHoverTime = 0xdeadbeef; \
12574     SetLastError(0xdeadbeef); \
12575     ret = pTrackMouseEvent(&tme); \
12576     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
12577     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
12578     ok(tme.dwFlags == (expected_track_flags), \
12579        "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
12580     ok(tme.hwndTrack == (expected_track_hwnd), \
12581        "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
12582     ok(tme.dwHoverTime == (expected_hover_time), \
12583        "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
12584 
12585 #define track_hover_cancel(track_hwnd) \
12586     tme.cbSize = sizeof(tme); \
12587     tme.dwFlags = TME_HOVER | TME_CANCEL; \
12588     tme.hwndTrack = track_hwnd; \
12589     tme.dwHoverTime = 0xdeadbeef; \
12590     SetLastError(0xdeadbeef); \
12591     ret = pTrackMouseEvent(&tme); \
12592     ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
12593 
12594     default_hover_time = 0xdeadbeef;
12595     SetLastError(0xdeadbeef);
12596     ret = SystemParametersInfoA(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
12597     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
12598        "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
12599     if (!ret) default_hover_time = 400;
12600     trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
12601 
12602     SetLastError(0xdeadbeef);
12603     ret = SystemParametersInfoA(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
12604     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
12605        "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
12606     if (!ret) hover_width = 4;
12607     SetLastError(0xdeadbeef);
12608     ret = SystemParametersInfoA(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
12609     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
12610        "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
12611     if (!ret) hover_height = 4;
12612     trace("hover rect is %u x %d\n", hover_width, hover_height);
12613 
12614     hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
12615 			  WS_OVERLAPPEDWINDOW | WS_VISIBLE,
12616 			  CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
12617 			  NULL, NULL, 0);
12618     assert(hwnd);
12619 
12620     hchild = CreateWindowExA(0, "TestWindowClass", NULL,
12621 			  WS_CHILD | WS_BORDER | WS_VISIBLE,
12622 			  50, 50, 200, 200, hwnd,
12623 			  NULL, NULL, 0);
12624     assert(hchild);
12625 
12626     SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
12627     flush_events();
12628     flush_sequence();
12629 
12630     tme.cbSize = 0;
12631     tme.dwFlags = TME_QUERY;
12632     tme.hwndTrack = (HWND)0xdeadbeef;
12633     tme.dwHoverTime = 0xdeadbeef;
12634     SetLastError(0xdeadbeef);
12635     ret = pTrackMouseEvent(&tme);
12636     ok(!ret, "TrackMouseEvent should fail\n");
12637     ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef),
12638        "not expected error %u\n", GetLastError());
12639 
12640     tme.cbSize = sizeof(tme);
12641     tme.dwFlags = TME_HOVER;
12642     tme.hwndTrack = (HWND)0xdeadbeef;
12643     tme.dwHoverTime = 0xdeadbeef;
12644     SetLastError(0xdeadbeef);
12645     ret = pTrackMouseEvent(&tme);
12646     ok(!ret, "TrackMouseEvent should fail\n");
12647     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
12648        "not expected error %u\n", GetLastError());
12649 
12650     tme.cbSize = sizeof(tme);
12651     tme.dwFlags = TME_HOVER | TME_CANCEL;
12652     tme.hwndTrack = (HWND)0xdeadbeef;
12653     tme.dwHoverTime = 0xdeadbeef;
12654     SetLastError(0xdeadbeef);
12655     ret = pTrackMouseEvent(&tme);
12656     ok(!ret, "TrackMouseEvent should fail\n");
12657     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
12658        "not expected error %u\n", GetLastError());
12659 
12660     GetWindowRect(hwnd, &rc_parent);
12661     GetWindowRect(hchild, &rc_child);
12662     SetCursorPos(rc_child.left - 10, rc_child.top - 10);
12663 
12664     /* Process messages so that the system updates its internal current
12665      * window and hittest, otherwise TrackMouseEvent calls don't have any
12666      * effect.
12667      */
12668     flush_events();
12669     flush_sequence();
12670 
12671     track_query(0, NULL, 0);
12672     track_hover(hchild, 0);
12673     track_query(0, NULL, 0);
12674 
12675     flush_events();
12676     flush_sequence();
12677 
12678     track_hover(hwnd, 0);
12679     tme.cbSize = sizeof(tme);
12680     tme.dwFlags = TME_QUERY;
12681     tme.hwndTrack = (HWND)0xdeadbeef;
12682     tme.dwHoverTime = 0xdeadbeef;
12683     SetLastError(0xdeadbeef);
12684     ret = pTrackMouseEvent(&tme);
12685     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());
12686     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize);
12687     if (!tme.dwFlags)
12688     {
12689         skip( "Cursor not inside window, skipping TrackMouseEvent tests\n" );
12690         DestroyWindow( hwnd );
12691         return;
12692     }
12693     ok(tme.dwFlags == TME_HOVER, "wrong tme.dwFlags %08x, expected TME_HOVER\n", tme.dwFlags);
12694     ok(tme.hwndTrack == hwnd, "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, hwnd);
12695     ok(tme.dwHoverTime == default_hover_time, "wrong tme.dwHoverTime %u, expected %u\n",
12696        tme.dwHoverTime, default_hover_time);
12697 
12698     pump_msg_loop_timeout(default_hover_time, FALSE);
12699     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
12700 
12701     track_query(0, NULL, 0);
12702 
12703     track_hover(hwnd, HOVER_DEFAULT);
12704     track_query(TME_HOVER, hwnd, default_hover_time);
12705 
12706     Sleep(default_hover_time / 2);
12707     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
12708     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
12709 
12710     track_query(TME_HOVER, hwnd, default_hover_time);
12711 
12712     pump_msg_loop_timeout(default_hover_time, FALSE);
12713     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
12714 
12715     track_query(0, NULL, 0);
12716 
12717     track_hover(hwnd, HOVER_DEFAULT);
12718     track_query(TME_HOVER, hwnd, default_hover_time);
12719 
12720     pump_msg_loop_timeout(default_hover_time, TRUE);
12721     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
12722 
12723     track_query(0, NULL, 0);
12724 
12725     track_hover(hwnd, HOVER_DEFAULT);
12726     track_query(TME_HOVER, hwnd, default_hover_time);
12727     track_hover_cancel(hwnd);
12728 
12729     DestroyWindow(hwnd);
12730 
12731 #undef track_hover
12732 #undef track_query
12733 #undef track_hover_cancel
12734 }
12735 
12736 
12737 static const struct message WmSetWindowRgn[] = {
12738     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
12739     { WM_NCCALCSIZE, sent|wparam, 1 },
12740     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
12741     { WM_GETTEXT, sent|defwinproc|optional },
12742     { WM_ERASEBKGND, sent|optional },
12743     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
12744     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12745     { 0 }
12746 };
12747 
12748 static const struct message WmSetWindowRgn_no_redraw[] = {
12749     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
12750     { WM_NCCALCSIZE, sent|wparam, 1 },
12751     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
12752     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12753     { 0 }
12754 };
12755 
12756 static const struct message WmSetWindowRgn_clear[] = {
12757     { WM_WINDOWPOSCHANGING, sent/*|wparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */ },
12758     { WM_NCCALCSIZE, sent|wparam, 1 },
12759     { WM_NCPAINT, sent|optional },
12760     { WM_GETTEXT, sent|defwinproc|optional },
12761     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
12762     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
12763     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
12764     { WM_NCPAINT, sent|optional },
12765     { WM_GETTEXT, sent|defwinproc|optional },
12766     { WM_ERASEBKGND, sent|optional },
12767     { WM_WINDOWPOSCHANGING, sent|optional },
12768     { WM_NCCALCSIZE, sent|optional|wparam, 1 },
12769     { WM_NCPAINT, sent|optional },
12770     { WM_GETTEXT, sent|defwinproc|optional },
12771     { WM_ERASEBKGND, sent|optional },
12772     { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
12773     { WM_NCCALCSIZE, sent|optional|wparam, 1 },
12774     { WM_NCPAINT, sent|optional },
12775     { WM_GETTEXT, sent|defwinproc|optional },
12776     { WM_ERASEBKGND, sent|optional },
12777     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12778     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12779     { 0 }
12780 };
12781 
12782 static void test_SetWindowRgn(void)
12783 {
12784     HRGN hrgn;
12785     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
12786                                 100, 100, 200, 200, 0, 0, 0, NULL);
12787     ok( hwnd != 0, "Failed to create overlapped window\n" );
12788 
12789     ShowWindow( hwnd, SW_SHOW );
12790     UpdateWindow( hwnd );
12791     flush_events();
12792     flush_sequence();
12793 
12794     trace("testing SetWindowRgn\n");
12795     hrgn = CreateRectRgn( 0, 0, 150, 150 );
12796     SetWindowRgn( hwnd, hrgn, TRUE );
12797     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
12798 
12799     hrgn = CreateRectRgn( 30, 30, 160, 160 );
12800     SetWindowRgn( hwnd, hrgn, FALSE );
12801     ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
12802 
12803     hrgn = CreateRectRgn( 0, 0, 180, 180 );
12804     SetWindowRgn( hwnd, hrgn, TRUE );
12805     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
12806 
12807     SetWindowRgn( hwnd, 0, TRUE );
12808     ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
12809 
12810     DestroyWindow( hwnd );
12811 }
12812 
12813 /*************************** ShowWindow() test ******************************/
12814 static const struct message WmShowNormal[] = {
12815     { WM_SHOWWINDOW, sent|wparam, 1 },
12816     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
12817     { HCBT_ACTIVATE, hook },
12818     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
12819     { HCBT_SETFOCUS, hook },
12820     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12821     { 0 }
12822 };
12823 static const struct message WmShow[] = {
12824     { WM_SHOWWINDOW, sent|wparam, 1 },
12825     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
12826     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12827     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12828     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12829     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12830     { 0 }
12831 };
12832 static const struct message WmShowNoActivate_1[] = {
12833     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
12834     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12835     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12836     { WM_MOVE, sent|defwinproc|optional },
12837     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
12838     { 0 }
12839 };
12840 static const struct message WmShowNoActivate_2[] = {
12841     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
12842     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12843     { HCBT_ACTIVATE, hook|optional },
12844     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
12845     { HCBT_SETFOCUS, hook|optional },
12846     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12847     { WM_MOVE, sent|defwinproc },
12848     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
12849     { HCBT_SETFOCUS, hook|optional },
12850     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
12851     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
12852     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12853     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
12854     { 0 }
12855 };
12856 static const struct message WmShowNA_1[] = {
12857     { WM_SHOWWINDOW, sent|wparam, 1 },
12858     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
12859     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12860     { 0 }
12861 };
12862 static const struct message WmShowNA_2[] = {
12863     { WM_SHOWWINDOW, sent|wparam, 1 },
12864     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
12865     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12866     { 0 }
12867 };
12868 static const struct message WmRestore_1[] = {
12869     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
12870     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12871     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12872     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12873     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12874     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12875     { WM_MOVE, sent|defwinproc },
12876     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
12877     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
12878     { 0 }
12879 };
12880 static const struct message WmRestore_2[] = {
12881     { WM_SHOWWINDOW, sent|wparam, 1 },
12882     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
12883     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12884     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12885     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12886     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12887     { 0 }
12888 };
12889 static const struct message WmRestore_3[] = {
12890     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
12891     { WM_GETMINMAXINFO, sent },
12892     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12893     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
12894     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
12895     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
12896     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12897     { WM_MOVE, sent|defwinproc },
12898     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
12899     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
12900     { 0 }
12901 };
12902 static const struct message WmRestore_4[] = {
12903     { HCBT_MINMAX, hook|lparam|optional, 0, SW_RESTORE },
12904     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12905     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12906     { WM_MOVE, sent|defwinproc|optional },
12907     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
12908     { 0 }
12909 };
12910 static const struct message WmRestore_5[] = {
12911     { HCBT_MINMAX, hook|lparam|optional, 0, SW_SHOWNORMAL },
12912     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12913     { HCBT_ACTIVATE, hook|optional },
12914     { HCBT_SETFOCUS, hook|optional },
12915     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12916     { WM_MOVE, sent|defwinproc|optional },
12917     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
12918     { 0 }
12919 };
12920 static const struct message WmHide_1[] = {
12921     { WM_SHOWWINDOW, sent|wparam, 0 },
12922     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOACTIVATE },
12923     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOACTIVATE },
12924     { HCBT_ACTIVATE, hook|optional },
12925     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
12926     { 0 }
12927 };
12928 static const struct message WmHide_2[] = {
12929     { WM_SHOWWINDOW, sent|wparam, 0 },
12930     { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
12931     { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
12932     { HCBT_ACTIVATE, hook|optional },
12933     { 0 }
12934 };
12935 static const struct message WmHide_3[] = {
12936     { WM_SHOWWINDOW, sent|wparam, 0 },
12937     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
12938     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12939     { HCBT_SETFOCUS, hook|optional },
12940     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
12941     { 0 }
12942 };
12943 static const struct message WmShowMinimized_1[] = {
12944     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
12945     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12946     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12947     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12948     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12949     { WM_MOVE, sent|defwinproc },
12950     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
12951     { 0 }
12952 };
12953 static const struct message WmMinimize_1[] = {
12954     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
12955     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12956     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
12957     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12958     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12959     { WM_MOVE, sent|defwinproc },
12960     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
12961     { 0 }
12962 };
12963 static const struct message WmMinimize_2[] = {
12964     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
12965     { HCBT_SETFOCUS, hook|optional },
12966     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12967     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12968     { WM_MOVE, sent|defwinproc },
12969     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
12970     { 0 }
12971 };
12972 static const struct message WmMinimize_3[] = {
12973     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
12974     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12975     { HCBT_ACTIVATE, hook|optional },
12976     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
12977     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12978     { WM_MOVE, sent|defwinproc },
12979     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
12980     { 0 }
12981 };
12982 static const struct message WmShowMinNoActivate[] = {
12983     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
12984     { WM_WINDOWPOSCHANGING, sent },
12985     { WM_WINDOWPOSCHANGED, sent },
12986     { WM_MOVE, sent|defwinproc|optional },
12987     { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
12988     { 0 }
12989 };
12990 static const struct message WmMinMax_1[] = {
12991     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
12992     { 0 }
12993 };
12994 static const struct message WmMinMax_2[] = {
12995     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
12996     { WM_GETMINMAXINFO, sent|optional },
12997     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED },
12998     { HCBT_ACTIVATE, hook|optional },
12999     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13000     { HCBT_SETFOCUS, hook|optional },
13001     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13002     { WM_MOVE, sent|defwinproc|optional },
13003     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MAXIMIZED },
13004     { HCBT_SETFOCUS, hook|optional },
13005     { 0 }
13006 };
13007 static const struct message WmMinMax_3[] = {
13008     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
13009     { HCBT_SETFOCUS, hook|optional },
13010     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13011     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13012     { WM_MOVE, sent|defwinproc|optional },
13013     { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
13014     { 0 }
13015 };
13016 static const struct message WmMinMax_4[] = {
13017     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
13018     { 0 }
13019 };
13020 static const struct message WmShowMaximized_1[] = {
13021     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
13022     { WM_GETMINMAXINFO, sent },
13023     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13024     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13025     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13026     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13027     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13028     { WM_MOVE, sent|defwinproc },
13029     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
13030     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
13031     { 0 }
13032 };
13033 static const struct message WmShowMaximized_2[] = {
13034     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
13035     { WM_GETMINMAXINFO, sent },
13036     { WM_WINDOWPOSCHANGING, sent|optional },
13037     { HCBT_ACTIVATE, hook|optional },
13038     { WM_WINDOWPOSCHANGED, sent|optional },
13039     { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
13040     { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
13041     { WM_WINDOWPOSCHANGING, sent|optional },
13042     { HCBT_SETFOCUS, hook|optional },
13043     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13044     { WM_MOVE, sent|defwinproc },
13045     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
13046     { HCBT_SETFOCUS, hook|optional },
13047     { 0 }
13048 };
13049 static const struct message WmShowMaximized_3[] = {
13050     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
13051     { WM_GETMINMAXINFO, sent|optional },
13052     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13053     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13054     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13055     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13056     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13057     { WM_MOVE, sent|defwinproc|optional },
13058     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
13059     { 0 }
13060 };
13061 
13062 static void test_ShowWindow(void)
13063 {
13064     /* ShowWindow commands in random order */
13065     static const struct
13066     {
13067         INT cmd; /* ShowWindow command */
13068         LPARAM ret; /* ShowWindow return value */
13069         DWORD style; /* window style after the command */
13070         const struct message *msg; /* message sequence the command produces */
13071         INT wp_cmd, wp_flags; /* window placement after the command */
13072         POINT wp_min, wp_max; /* window placement after the command */
13073         BOOL todo_msg; /* message sequence doesn't match what Wine does */
13074     } sw[] =
13075     {
13076 /*  1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal,
13077            SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
13078 /*  2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq,
13079            SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
13080 /*  3 */ { SW_HIDE, TRUE, 0, WmHide_1,
13081            SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
13082 /*  4 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13083            SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
13084 /*  5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1,
13085            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13086 /*  6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1,
13087            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13088 /*  7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1,
13089            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13090 /*  8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
13091            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13092 /*  9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1,
13093            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13094 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
13095            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13096 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1,
13097            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13098 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq,
13099            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13100 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1,
13101            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13102 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
13103            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13104 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2,
13105            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13106 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13107            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13108 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow,
13109            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13110 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
13111            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13112 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
13113            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13114 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
13115            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13116 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13117            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13118 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate,
13119            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, TRUE },
13120 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4,
13121            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13122 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13123            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13124 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
13125            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13126 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1,
13127            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13128 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2,
13129            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13130 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13131            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13132 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
13133            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13134 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1,
13135            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13136 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
13137            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13138 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3,
13139            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13140 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13141            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13142 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, /* what does this mean?! */
13143            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13144 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq,
13145            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13146 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13147            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13148 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2,
13149            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13150 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
13151            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13152 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
13153            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13154 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2,
13155            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13156 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
13157            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13158 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2,
13159            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13160 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
13161            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13162 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
13163            SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13164 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
13165            SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13166 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3,
13167            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13168 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4,
13169            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13170 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3,
13171            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13172 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq,
13173            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13174 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
13175            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13176 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
13177            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13178 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1,
13179            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13180 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13181            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13182 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3,
13183            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13184 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13185            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13186 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2,
13187            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13188 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
13189            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE }
13190     };
13191     HWND hwnd;
13192     DWORD style;
13193     LPARAM ret;
13194     INT i;
13195     WINDOWPLACEMENT wp;
13196     RECT win_rc, work_rc = {0, 0, 0, 0};
13197 
13198 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
13199     hwnd = CreateWindowExA(0, "ShowWindowClass", NULL, WS_BASE,
13200                           120, 120, 90, 90,
13201                           0, 0, 0, NULL);
13202     assert(hwnd);
13203 
13204     style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
13205     ok(style == 0, "expected style 0, got %08x\n", style);
13206 
13207     flush_events();
13208     flush_sequence();
13209 
13210     if (pGetMonitorInfoA && pMonitorFromPoint)
13211     {
13212         HMONITOR hmon;
13213         MONITORINFO mi;
13214         POINT pt = {0, 0};
13215 
13216         SetLastError(0xdeadbeef);
13217         hmon = pMonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
13218         ok(hmon != 0, "MonitorFromPoint error %u\n", GetLastError());
13219 
13220         mi.cbSize = sizeof(mi);
13221         SetLastError(0xdeadbeef);
13222         ret = pGetMonitorInfoA(hmon, &mi);
13223         ok(ret, "GetMonitorInfo error %u\n", GetLastError());
13224         trace("monitor %s, work %s\n", wine_dbgstr_rect(&mi.rcMonitor),
13225               wine_dbgstr_rect(&mi.rcWork));
13226         work_rc = mi.rcWork;
13227     }
13228 
13229     GetWindowRect(hwnd, &win_rc);
13230     OffsetRect(&win_rc, -work_rc.left, -work_rc.top);
13231 
13232     wp.length = sizeof(wp);
13233     SetLastError(0xdeadbeaf);
13234     ret = GetWindowPlacement(hwnd, &wp);
13235     ok(ret, "GetWindowPlacement error %u\n", GetLastError());
13236     ok(wp.flags == 0, "expected 0, got %#x\n", wp.flags);
13237     ok(wp.showCmd == SW_SHOWNORMAL, "expected SW_SHOWNORMAL, got %d\n", wp.showCmd);
13238     ok(wp.ptMinPosition.x == -1 && wp.ptMinPosition.y == -1,
13239        "expected -1,-1 got %d,%d\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
13240     ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
13241        "expected -1,-1 got %d,%d\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
13242     todo_wine_if (work_rc.left || work_rc.top) /* FIXME: remove once Wine is fixed */
13243     ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n", wine_dbgstr_rect(&win_rc),
13244        wine_dbgstr_rect(&wp.rcNormalPosition));
13245 
13246     for (i = 0; i < sizeof(sw)/sizeof(sw[0]); i++)
13247     {
13248         static const char * const sw_cmd_name[13] =
13249         {
13250             "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
13251             "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
13252             "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
13253             "SW_NORMALNA" /* 0xCC */
13254         };
13255         char comment[64];
13256         INT idx; /* index into the above array of names */
13257 
13258         idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
13259 
13260         style = GetWindowLongA(hwnd, GWL_STYLE);
13261         trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
13262         ret = ShowWindow(hwnd, sw[i].cmd);
13263         ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
13264         style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
13265         ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
13266 
13267         sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
13268         ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
13269 
13270         wp.length = sizeof(wp);
13271         SetLastError(0xdeadbeaf);
13272         ret = GetWindowPlacement(hwnd, &wp);
13273         ok(ret, "GetWindowPlacement error %u\n", GetLastError());
13274         ok(wp.flags == sw[i].wp_flags, "expected %#x, got %#x\n", sw[i].wp_flags, wp.flags);
13275         ok(wp.showCmd == sw[i].wp_cmd, "expected %d, got %d\n", sw[i].wp_cmd, wp.showCmd);
13276 
13277         /* NT moves the minimized window to -32000,-32000, win9x to 3000,3000 */
13278         if ((wp.ptMinPosition.x + work_rc.left == -32000 && wp.ptMinPosition.y + work_rc.top == -32000) ||
13279             (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000))
13280         {
13281             ok((wp.ptMinPosition.x + work_rc.left == sw[i].wp_min.x && wp.ptMinPosition.y + work_rc.top == sw[i].wp_min.y) ||
13282                (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000),
13283                "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
13284         }
13285         else
13286         {
13287             ok(wp.ptMinPosition.x == sw[i].wp_min.x && wp.ptMinPosition.y == sw[i].wp_min.y,
13288                "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
13289         }
13290 
13291         todo_wine_if(wp.ptMaxPosition.x != sw[i].wp_max.x || wp.ptMaxPosition.y != sw[i].wp_max.y)
13292         ok(wp.ptMaxPosition.x == sw[i].wp_max.x && wp.ptMaxPosition.y == sw[i].wp_max.y,
13293            "expected %d,%d got %d,%d\n", sw[i].wp_max.x, sw[i].wp_max.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y);
13294 
13295 if (0) /* FIXME: Wine behaves completely different here */
13296         ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n",
13297            wine_dbgstr_rect(&win_rc), wine_dbgstr_rect(&wp.rcNormalPosition));
13298     }
13299     DestroyWindow(hwnd);
13300     flush_events();
13301 }
13302 
13303 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13304 {
13305     struct recvd_message msg;
13306 
13307     if (ignore_message( message )) return 0;
13308 
13309     msg.hwnd = hwnd;
13310     msg.message = message;
13311     msg.flags = sent|wparam|lparam;
13312     msg.wParam = wParam;
13313     msg.lParam = lParam;
13314     msg.descr = "dialog";
13315     add_message(&msg);
13316 
13317     /* calling DefDlgProc leads to a recursion under XP */
13318 
13319     switch (message)
13320     {
13321     case WM_INITDIALOG:
13322         return lParam;
13323 
13324     case WM_GETDLGCODE:
13325         return 0;
13326     }
13327     return 1;
13328 }
13329 
13330 static WNDPROC orig_edit_proc;
13331 static LRESULT WINAPI dlg_creation_edit_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
13332 {
13333     struct recvd_message msg;
13334 
13335     if (ignore_message( message )) return 0;
13336 
13337     msg.hwnd = hwnd;
13338     msg.message = message;
13339     msg.flags = sent|wparam|lparam;
13340     msg.wParam = wp;
13341     msg.lParam = lp;
13342     msg.descr = "edit";
13343     add_message(&msg);
13344 
13345     return CallWindowProcW(orig_edit_proc, hwnd, message, wp, lp);
13346 }
13347 
13348 static INT_PTR WINAPI test_dlg_proc2(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13349 {
13350     struct recvd_message msg;
13351 
13352     if (ignore_message( message )) return 0;
13353 
13354     msg.hwnd = hwnd;
13355     msg.message = message;
13356     msg.flags = sent|wparam|lparam|parent;
13357     msg.wParam = wParam;
13358     msg.lParam = lParam;
13359     msg.descr = "dialog";
13360     add_message(&msg);
13361 
13362     if (message == WM_INITDIALOG)
13363     {
13364         orig_edit_proc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hwnd, 200),
13365                 GWLP_WNDPROC, (LONG_PTR)dlg_creation_edit_proc);
13366     }
13367 
13368     return 1;
13369 }
13370 
13371 static INT_PTR WINAPI test_dlg_proc3(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13372 {
13373     ok( 0, "should not be called since DefDlgProc is not used\n" );
13374     return 0;
13375 }
13376 
13377 static LRESULT WINAPI test_dlg_proc4(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13378 {
13379     struct recvd_message msg;
13380 
13381     if (!ignore_message( message ))
13382     {
13383         msg.hwnd = hwnd;
13384         msg.message = message;
13385         msg.flags = sent|wparam|lparam|parent;
13386         msg.wParam = wParam;
13387         msg.lParam = lParam;
13388         msg.descr = "dialog";
13389         add_message(&msg);
13390     }
13391     if (message == WM_INITDIALOG)
13392     {
13393         orig_edit_proc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hwnd, 200),
13394                 GWLP_WNDPROC, (LONG_PTR)dlg_creation_edit_proc);
13395         return 1;
13396     }
13397     return DefWindowProcW( hwnd, message, wParam, lParam );
13398 }
13399 
13400 static const struct message WmDefDlgSetFocus_1[] = {
13401     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13402     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
13403     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
13404     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
13405     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
13406     { HCBT_SETFOCUS, hook },
13407     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
13408     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13409     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
13410     { WM_SETFOCUS, sent|wparam, 0 },
13411     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
13412     { WM_CTLCOLOREDIT, sent },
13413     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
13414     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13415     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13416     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13417     { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
13418     { 0 }
13419 };
13420 static const struct message WmDefDlgSetFocus_2[] = {
13421     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13422     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
13423     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
13424     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
13425     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
13426     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13427     { WM_CTLCOLOREDIT, sent|optional }, /* XP */
13428     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13429     { 0 }
13430 };
13431 /* Creation of a dialog */
13432 static const struct message WmCreateDialogParamSeq_0[] = {
13433     { HCBT_CREATEWND, hook },
13434     { WM_NCCREATE, sent },
13435     { WM_NCCALCSIZE, sent|wparam, 0 },
13436     { WM_CREATE, sent },
13437     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13438     { WM_SIZE, sent|wparam, SIZE_RESTORED },
13439     { WM_MOVE, sent },
13440     { WM_SETFONT, sent },
13441     { WM_INITDIALOG, sent },
13442     { WM_CHANGEUISTATE, sent|optional },
13443     { 0 }
13444 };
13445 /* Creation of a dialog */
13446 static const struct message WmCreateDialogParamSeq_1[] = {
13447     { HCBT_CREATEWND, hook },
13448     { WM_NCCREATE, sent },
13449     { WM_NCCALCSIZE, sent|wparam, 0 },
13450     { WM_CREATE, sent },
13451     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13452     { WM_SIZE, sent|wparam, SIZE_RESTORED },
13453     { WM_MOVE, sent },
13454     { WM_SETFONT, sent },
13455     { WM_INITDIALOG, sent },
13456     { WM_GETDLGCODE, sent|wparam|lparam|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
13457     { HCBT_SETFOCUS, hook },
13458     { HCBT_ACTIVATE, hook },
13459     { WM_QUERYNEWPALETTE, sent|optional },
13460     { WM_PALETTEISCHANGING, sent|optional },
13461     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13462     { WM_ACTIVATEAPP, sent|wparam, 1 },
13463     { WM_NCACTIVATE, sent },
13464     { WM_ACTIVATE, sent|wparam, 1 },
13465     { WM_SETFOCUS, sent },
13466     { WM_CHANGEUISTATE, sent|optional },
13467     { 0 }
13468 };
13469 /* Creation of a dialog */
13470 static const struct message WmCreateDialogParamSeq_2[] = {
13471     { HCBT_CREATEWND, hook },
13472     { WM_NCCREATE, sent },
13473     { WM_NCCALCSIZE, sent|wparam, 0 },
13474     { WM_CREATE, sent },
13475     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13476     { WM_SIZE, sent|wparam, SIZE_RESTORED },
13477     { WM_MOVE, sent },
13478     { WM_CHANGEUISTATE, sent|optional },
13479     { 0 }
13480 };
13481 
13482 static const struct message WmCreateDialogParamSeq_3[] = {
13483     { HCBT_CREATEWND, hook },
13484     { WM_SETFONT, sent|parent },
13485     { WM_INITDIALOG, sent|parent },
13486     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13487     { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
13488     { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13489     { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13490     { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13491     { HCBT_ACTIVATE, hook },
13492     { WM_QUERYNEWPALETTE, sent|parent|optional }, /* TODO: this message should not be sent */
13493     { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13494     { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13495     { WM_ACTIVATEAPP, sent|parent|wparam, 1 },
13496     { WM_NCACTIVATE, sent|parent },
13497     { WM_ACTIVATE, sent|parent|wparam, 1 },
13498     { WM_SETFOCUS, sent },
13499     { WM_COMMAND, sent|parent|wparam, MAKELONG(200, EN_SETFOCUS) },
13500     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13501     { WM_USER, sent|parent },
13502     { WM_CHANGEUISTATE, sent|parent|optional },
13503     { 0 }
13504 };
13505 
13506 static const struct message WmCreateDialogParamSeq_4[] = {
13507     { HCBT_CREATEWND, hook },
13508     { WM_NCCREATE, sent|parent },
13509     { WM_NCCALCSIZE, sent|parent|wparam, 0 },
13510     { WM_CREATE, sent|parent },
13511     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13512     { WM_SIZE, sent|parent|wparam, SIZE_RESTORED },
13513     { WM_MOVE, sent|parent },
13514     { WM_SETFONT, sent|parent },
13515     { WM_INITDIALOG, sent|parent },
13516     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13517     { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
13518     { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13519     { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13520     { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13521     { HCBT_ACTIVATE, hook },
13522     { WM_QUERYNEWPALETTE, sent|parent|optional }, /* TODO: this message should not be sent */
13523     { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13524     { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13525     { WM_ACTIVATEAPP, sent|parent|wparam, 1 },
13526     { WM_NCACTIVATE, sent|parent },
13527     { WM_ACTIVATE, sent|parent|wparam, 1 },
13528     { HCBT_SETFOCUS, hook },
13529     { WM_SETFOCUS, sent|parent },
13530     { WM_KILLFOCUS, sent|parent },
13531     { WM_SETFOCUS, sent },
13532     { WM_COMMAND, sent|parent|wparam, MAKELONG(200, EN_SETFOCUS) },
13533     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13534     { WM_USER, sent|parent },
13535     { WM_CHANGEUISTATE, sent|parent|optional },
13536     { WM_UPDATEUISTATE, sent|parent|optional },
13537     { WM_UPDATEUISTATE, sent|optional },
13538     { 0 }
13539 };
13540 
13541 static void test_dialog_messages(void)
13542 {
13543     WNDCLASSA cls;
13544     HWND hdlg, hedit1, hedit2, hfocus, parent, child, child2;
13545     LRESULT ret;
13546 
13547 #define set_selection(hctl, start, end) \
13548     ret = SendMessageA(hctl, EM_SETSEL, start, end); \
13549     ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
13550 
13551 #define check_selection(hctl, start, end) \
13552     ret = SendMessageA(hctl, EM_GETSEL, 0, 0); \
13553     ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
13554 
13555     subclass_edit();
13556 
13557     hdlg = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
13558                           WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
13559                           0, 0, 100, 100, 0, 0, 0, NULL);
13560     ok(hdlg != 0, "Failed to create custom dialog window\n");
13561 
13562     hedit1 = CreateWindowExA(0, "my_edit_class", NULL,
13563                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
13564                            0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
13565     ok(hedit1 != 0, "Failed to create edit control\n");
13566     hedit2 = CreateWindowExA(0, "my_edit_class", NULL,
13567                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
13568                            0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
13569     ok(hedit2 != 0, "Failed to create edit control\n");
13570 
13571     SendMessageA(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
13572     SendMessageA(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
13573 
13574     hfocus = GetFocus();
13575     ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
13576 
13577     SetFocus(hedit2);
13578     hfocus = GetFocus();
13579     ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
13580 
13581     check_selection(hedit1, 0, 0);
13582     check_selection(hedit2, 0, 0);
13583 
13584     set_selection(hedit2, 0, -1);
13585     check_selection(hedit2, 0, 3);
13586 
13587     SetFocus(0);
13588     hfocus = GetFocus();
13589     ok(hfocus == 0, "wrong focus %p\n", hfocus);
13590 
13591     flush_sequence();
13592     ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
13593     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
13594     ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
13595 
13596     hfocus = GetFocus();
13597     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
13598 
13599     check_selection(hedit1, 0, 5);
13600     check_selection(hedit2, 0, 3);
13601 
13602     flush_sequence();
13603     ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
13604     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
13605     ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
13606 
13607     hfocus = GetFocus();
13608     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
13609 
13610     check_selection(hedit1, 0, 5);
13611     check_selection(hedit2, 0, 3);
13612 
13613     EndDialog(hdlg, 0);
13614     DestroyWindow(hedit1);
13615     DestroyWindow(hedit2);
13616     DestroyWindow(hdlg);
13617     flush_sequence();
13618 
13619 #undef set_selection
13620 #undef check_selection
13621 
13622     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
13623     cls.lpszClassName = "MyDialogClass";
13624     cls.hInstance = GetModuleHandleA(NULL);
13625     /* need a cast since a dlgproc is used as a wndproc */
13626     cls.lpfnWndProc = test_dlg_proc;
13627     if (!RegisterClassA(&cls)) assert(0);
13628 
13629     SetFocus(0);
13630     flush_sequence();
13631     hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
13632     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13633     ok_sequence(WmCreateDialogParamSeq_0, "CreateDialogParam_0", FALSE);
13634     hfocus = GetFocus();
13635     ok(hfocus == 0, "wrong focus %p\n", hfocus);
13636     EndDialog(hdlg, 0);
13637     DestroyWindow(hdlg);
13638     flush_sequence();
13639 
13640     SetFocus(0);
13641     flush_sequence();
13642     hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 1);
13643     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13644     ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
13645     hfocus = GetFocus();
13646     ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
13647     EndDialog(hdlg, 0);
13648     DestroyWindow(hdlg);
13649     flush_sequence();
13650 
13651     hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
13652     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13653     ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
13654     EndDialog(hdlg, 0);
13655     DestroyWindow(hdlg);
13656     flush_sequence();
13657 
13658     hdlg = CreateDialogParamA(0, "FOCUS_TEST_DIALOG_3", 0, test_dlg_proc2, 0);
13659     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13660     ok_sequence(WmCreateDialogParamSeq_3, "CreateDialogParam_3", TRUE);
13661     EndDialog(hdlg, 0);
13662     DestroyWindow(hdlg);
13663     flush_sequence();
13664 
13665     UnregisterClassA( cls.lpszClassName, cls.hInstance );
13666     cls.lpfnWndProc = test_dlg_proc4;
13667     ok( RegisterClassA(&cls), "failed to register class again\n" );
13668     hdlg = CreateDialogParamA(0, "FOCUS_TEST_DIALOG_4", 0, test_dlg_proc3, 0);
13669     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13670     ok_sequence(WmCreateDialogParamSeq_4, "CreateDialogParam_4", TRUE);
13671     EndDialog(hdlg, 0);
13672     DestroyWindow(hdlg);
13673     flush_sequence();
13674 
13675     UnregisterClassA(cls.lpszClassName, cls.hInstance);
13676 
13677     parent = CreateWindowExA(0, "TestParentClass", "Test parent",
13678                              WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13679                              100, 100, 200, 200, 0, 0, 0, NULL);
13680     ok (parent != 0, "Failed to create parent window\n");
13681 
13682     /* This child has no parent set. We will later call SetParent on it,
13683      * so that it will have a parent set, but no WS_CHILD style. */
13684     child = CreateWindowExA(0, "TestWindowClass", "Test child",
13685                             WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13686                             100, 100, 200, 200, 0, 0, 0, NULL);
13687     ok (child != 0, "Failed to create child window\n");
13688 
13689     /* This is a regular child window. When used as an owner, the other
13690      * child window will be used. */
13691     child2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2",
13692                              WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CHILD,
13693                              100, 100, 200, 200, child, 0, 0, NULL);
13694     ok (child2 != 0, "Failed to create child window\n");
13695 
13696     SetParent(child, parent);
13697     SetFocus(child);
13698 
13699     flush_sequence();
13700     DialogBoxA( 0, "TEST_DIALOG", child2, TestModalDlgProc2 );
13701     ok_sequence(WmModalDialogSeq_2, "ModalDialog2", TRUE);
13702 
13703     DestroyWindow(child2);
13704     DestroyWindow(child);
13705     DestroyWindow(parent);
13706     flush_sequence();
13707 }
13708 
13709 static void test_enddialog_seq(HWND dialog, HWND owner)
13710 {
13711     const struct message seq[] = {
13712         { WM_ENABLE, sent },
13713         { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13714         { HCBT_ACTIVATE, hook|wparam, (WPARAM)owner },
13715         { WM_NCACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13716         { WM_ACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13717         /* FIXME: Following two are optional because Wine sends WM_QUERYNEWPALETTE instead of WM_WINDOWPOSCHANGING */
13718         { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13719         { WM_QUERYNEWPALETTE, sent|optional },
13720         { WM_NCACTIVATE, sent|wparam|lparam, WA_ACTIVE, (LPARAM)dialog },
13721         { WM_GETTEXT, sent|optional|defwinproc },
13722         { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, (LPARAM)dialog },
13723         { HCBT_SETFOCUS, hook|wparam, (WPARAM)owner },
13724         { WM_KILLFOCUS, sent|wparam, (WPARAM)owner },
13725         { WM_SETFOCUS, sent|defwinproc|wparam, (WPARAM)dialog },
13726         { 0 }
13727     };
13728 
13729     flush_sequence();
13730     EndDialog(dialog, 0);
13731     ok_sequence(seq, "EndDialog", FALSE);
13732 }
13733 
13734 static void test_enddialog_seq2(HWND dialog, HWND owner)
13735 {
13736     const struct message seq[] = {
13737         { WM_ENABLE, parent|sent },
13738         { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13739         { HCBT_ACTIVATE, hook|wparam, (WPARAM)owner },
13740         { WM_NCACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13741         { WM_ACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13742         { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13743         { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13744         { HCBT_SETFOCUS, hook|wparam, (WPARAM)owner },
13745         { WM_KILLFOCUS, sent|wparam, (WPARAM)owner },
13746         { WM_SETFOCUS, sent|parent|defwinproc|wparam, (WPARAM)dialog },
13747         { 0 }
13748     };
13749 
13750     flush_sequence();
13751     EndDialog(dialog, 0);
13752     ok_sequence(seq, "EndDialog2", FALSE);
13753 }
13754 
13755 static void test_EndDialog(void)
13756 {
13757     HWND hparent, hother, hactive, hdlg, hchild;
13758     WNDCLASSA cls;
13759 
13760     hparent = CreateWindowExA(0, "TestParentClass", "Test parent",
13761                               WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_DISABLED,
13762                               100, 100, 200, 200, 0, 0, 0, NULL);
13763     ok (hparent != 0, "Failed to create parent window\n");
13764 
13765     hother = CreateWindowExA(0, "TestParentClass", "Test parent 2",
13766                               WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13767                               200, 100, 200, 200, 0, 0, 0, NULL);
13768     ok (hother != 0, "Failed to create parent window\n");
13769 
13770     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
13771     cls.lpszClassName = "MyDialogClass";
13772     cls.hInstance = GetModuleHandleA(NULL);
13773     cls.lpfnWndProc = test_dlg_proc;
13774     if (!RegisterClassA(&cls)) assert(0);
13775 
13776     flush_sequence();
13777     SetForegroundWindow(hother);
13778     hactive = GetForegroundWindow();
13779     ok(hother == hactive, "Wrong window has focus (%p != %p)\n", hother, hactive);
13780 
13781     /* create a dialog where the parent is disabled, this parent should be
13782      * enabled and receive focus when dialog exits */
13783     hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hparent, test_dlg_proc, 0);
13784     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13785     SetForegroundWindow(hdlg);
13786     hactive = GetForegroundWindow();
13787     ok(hdlg == hactive, "Wrong window has focus (%p != %p)\n", hdlg, hactive);
13788     EndDialog(hdlg, 0);
13789     ok(IsWindowEnabled(hparent), "parent is not enabled\n");
13790     hactive = GetForegroundWindow();
13791     ok(hparent == hactive, "Wrong window has focus (parent != active) (active: %p, parent: %p, dlg: %p, other: %p)\n", hactive, hparent, hdlg, hother);
13792     DestroyWindow(hdlg);
13793     flush_sequence();
13794 
13795     /* create a dialog where the parent is disabled and set active window to other window before calling EndDialog */
13796     EnableWindow(hparent, FALSE);
13797     hdlg = CreateWindowExA(0, "TestDialogClass", NULL,
13798                           WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
13799                           0, 0, 100, 100, hparent, 0, 0, NULL);
13800     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13801     flush_sequence();
13802     SetForegroundWindow(hother);
13803     flush_sequence();
13804     hactive = GetForegroundWindow();
13805     ok(hactive == hother, "Wrong foreground (%p != %p)\n", hactive, hother);
13806     hactive = GetActiveWindow();
13807     ok(hactive == hother, "Wrong active window (%p != %p)\n", hactive, hother);
13808     EndDialog(hdlg, 0);
13809     ok(IsWindowEnabled(hparent), "parent is not enabled\n");
13810     hactive = GetForegroundWindow();
13811     ok(hother == hactive, "Wrong window has focus (other != active) (active: %p, parent: %p, dlg: %p, other: %p)\n", hactive, hparent, hdlg, hother);
13812     DestroyWindow(hdlg);
13813     flush_sequence();
13814 
13815     DestroyWindow( hparent );
13816 
13817     hparent = CreateWindowExA(0, "TestParentClass", "Test parent",
13818                               WS_POPUP | WS_VISIBLE | WS_DISABLED,
13819                               100, 100, 200, 200, 0, 0, 0, NULL);
13820     ok (hparent != 0, "Failed to create parent window\n");
13821 
13822     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
13823                              WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_DISABLED,
13824                              0, 0, 0, 0, 0, 0, 0, NULL);
13825     ok (hchild != 0, "Failed to create child window\n");
13826 
13827     SetParent(hchild, hparent);
13828 
13829     flush_sequence();
13830     SetForegroundWindow(hother);
13831     hactive = GetForegroundWindow();
13832     ok(hother == hactive, "Wrong foreground window (%p != %p)\n", hother, hactive);
13833 
13834     hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hchild, test_dlg_proc, 0);
13835     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13836 
13837     SetForegroundWindow(hdlg);
13838     test_enddialog_seq(hdlg, hchild);
13839 
13840     hactive = GetForegroundWindow();
13841     ok(hactive == hchild, "Wrong foreground window (active: %p, parent: %p, dlg: %p, other: %p child: %p)\n", hactive, hparent, hdlg, hother, hchild);
13842 
13843     DestroyWindow(hdlg);
13844 
13845     /* Now set WS_CHILD style flag so that it's a real child and its parent will be dialog's owner. */
13846     SetWindowLongW(hchild, GWL_STYLE, GetWindowLongW(hchild, GWL_STYLE) | WS_CHILD);
13847 
13848     SetForegroundWindow(hother);
13849     hactive = GetForegroundWindow();
13850     ok(hother == hactive, "Wrong foreground window (%p != %p)\n", hother, hactive);
13851 
13852     hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hchild, test_dlg_proc, 0);
13853     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13854 
13855     SetForegroundWindow(hdlg);
13856     test_enddialog_seq2(hdlg, hparent);
13857 
13858     hactive = GetForegroundWindow();
13859     ok(hactive == hparent, "Wrong foreground window (active: %p, parent: %p, dlg: %p, other: %p child: %p)\n", hactive, hparent, hdlg, hother, hchild);
13860     DestroyWindow(hdlg);
13861     DestroyWindow(hchild);
13862     DestroyWindow(hparent);
13863     DestroyWindow(hother);
13864     flush_sequence();
13865 
13866     UnregisterClassA(cls.lpszClassName, cls.hInstance);
13867 }
13868 
13869 static void test_nullCallback(void)
13870 {
13871     HWND hwnd;
13872 
13873     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
13874                            100, 100, 200, 200, 0, 0, 0, NULL);
13875     ok (hwnd != 0, "Failed to create overlapped window\n");
13876 
13877     SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
13878     flush_events();
13879     DestroyWindow(hwnd);
13880 }
13881 
13882 /* SetActiveWindow( 0 ) hwnd visible */
13883 static const struct message SetActiveWindowSeq0[] =
13884 {
13885     { HCBT_ACTIVATE, hook|optional },
13886     { WM_NCACTIVATE, sent|wparam, 0 },
13887     { WM_GETTEXT, sent|defwinproc|optional },
13888     { WM_ACTIVATE, sent|wparam, 0 },
13889     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
13890     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
13891     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
13892     { WM_KILLFOCUS, sent|optional },
13893     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
13894     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13895     { WM_NCACTIVATE, sent|wparam|optional, 1 },
13896     { WM_GETTEXT, sent|defwinproc|optional },
13897     { WM_ACTIVATE, sent|wparam|optional, 1 },
13898     { HCBT_SETFOCUS, hook|optional },
13899     { WM_KILLFOCUS, sent|defwinproc|optional },
13900     { WM_IME_SETCONTEXT, sent|defwinproc|optional },
13901     { WM_IME_SETCONTEXT, sent|defwinproc|optional },
13902     { WM_IME_SETCONTEXT, sent|optional },
13903     { WM_IME_SETCONTEXT, sent|optional },
13904     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
13905     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13906     { WM_SETFOCUS, sent|defwinproc|optional },
13907     { WM_GETTEXT, sent|optional },
13908     { 0 }
13909 };
13910 /* SetActiveWindow( hwnd ) hwnd visible */
13911 static const struct message SetActiveWindowSeq1[] =
13912 {
13913     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
13914     { 0 }
13915 };
13916 /* SetActiveWindow( popup ) hwnd visible, popup visible */
13917 static const struct message SetActiveWindowSeq2[] =
13918 {
13919     { HCBT_ACTIVATE, hook },
13920     { WM_NCACTIVATE, sent|wparam, 0 },
13921     { WM_GETTEXT, sent|defwinproc|optional },
13922     { WM_ACTIVATE, sent|wparam, 0 },
13923     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
13924     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13925     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
13926     { WM_NCPAINT, sent|optional },
13927     { WM_GETTEXT, sent|defwinproc|optional },
13928     { WM_ERASEBKGND, sent|optional },
13929     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13930     { WM_NCACTIVATE, sent|wparam, 1 },
13931     { WM_GETTEXT, sent|defwinproc|optional },
13932     { WM_ACTIVATE, sent|wparam, 1 },
13933     { HCBT_SETFOCUS, hook },
13934     { WM_KILLFOCUS, sent|defwinproc },
13935     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
13936     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
13937     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
13938     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13939     { WM_SETFOCUS, sent|defwinproc },
13940     { WM_GETTEXT, sent|optional },
13941     { 0 }
13942 };
13943 
13944 /* SetActiveWindow( hwnd ) hwnd not visible */
13945 static const struct message SetActiveWindowSeq3[] =
13946 {
13947     { HCBT_ACTIVATE, hook },
13948     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
13949     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
13950     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
13951     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13952     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13953     { WM_ACTIVATEAPP, sent|wparam, 1 },
13954     { WM_ACTIVATEAPP, sent|wparam, 1 },
13955     { WM_NCACTIVATE, sent|wparam, 1 },
13956     { WM_ACTIVATE, sent|wparam, 1 },
13957     { HCBT_SETFOCUS, hook },
13958     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
13959     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13960     { WM_SETFOCUS, sent|defwinproc },
13961     { 0 }
13962 };
13963 /* SetActiveWindow( popup ) hwnd not visible, popup not visible */
13964 static const struct message SetActiveWindowSeq4[] =
13965 {
13966     { HCBT_ACTIVATE, hook },
13967     { WM_NCACTIVATE, sent|wparam, 0 },
13968     { WM_GETTEXT, sent|defwinproc|optional },
13969     { WM_ACTIVATE, sent|wparam, 0 },
13970     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
13971     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
13972     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
13973     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13974     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13975     { WM_NCACTIVATE, sent|wparam, 1 },
13976     { WM_GETTEXT, sent|defwinproc|optional },
13977     { WM_ACTIVATE, sent|wparam, 1 },
13978     { HCBT_SETFOCUS, hook },
13979     { WM_KILLFOCUS, sent|defwinproc },
13980     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
13981     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
13982     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
13983     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13984     { WM_SETFOCUS, sent|defwinproc },
13985     { 0 }
13986 };
13987 
13988 
13989 static void test_SetActiveWindow(void)
13990 {
13991     HWND hwnd, popup, ret;
13992 
13993     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
13994                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13995                            100, 100, 200, 200, 0, 0, 0, NULL);
13996 
13997     popup = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
13998                            WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_POPUP,
13999                            100, 100, 200, 200, hwnd, 0, 0, NULL);
14000 
14001     ok(hwnd != 0, "Failed to create overlapped window\n");
14002     ok(popup != 0, "Failed to create popup window\n");
14003     SetForegroundWindow( popup );
14004     flush_sequence();
14005 
14006     trace("SetActiveWindow(0)\n");
14007     ret = SetActiveWindow(0);
14008     ok( ret == popup, "Failed to SetActiveWindow(0)\n");
14009     ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", FALSE);
14010     flush_sequence();
14011 
14012     trace("SetActiveWindow(hwnd), hwnd visible\n");
14013     ret = SetActiveWindow(hwnd);
14014     if (ret == hwnd) ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE);
14015     flush_sequence();
14016 
14017     trace("SetActiveWindow(popup), hwnd visible, popup visible\n");
14018     ret = SetActiveWindow(popup);
14019     ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n");
14020     ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visible", FALSE);
14021     flush_sequence();
14022 
14023     ShowWindow(hwnd, SW_HIDE);
14024     ShowWindow(popup, SW_HIDE);
14025     flush_sequence();
14026 
14027     trace("SetActiveWindow(hwnd), hwnd not visible\n");
14028     ret = SetActiveWindow(hwnd);
14029     ok( ret == NULL, "SetActiveWindow(hwnd), hwnd not visible, previous is %p\n", ret );
14030     ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE);
14031     flush_sequence();
14032 
14033     trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n");
14034     ret = SetActiveWindow(popup);
14035     ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n");
14036     ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visible", TRUE);
14037     flush_sequence();
14038 
14039     trace("done\n");
14040 
14041     DestroyWindow(hwnd);
14042 }
14043 
14044 static const struct message SetForegroundWindowSeq[] =
14045 {
14046     { WM_NCACTIVATE, sent|wparam, 0 },
14047     { WM_GETTEXT, sent|defwinproc|optional },
14048     { WM_ACTIVATE, sent|wparam, 0 },
14049     { WM_ACTIVATEAPP, sent|wparam, 0 },
14050     { WM_KILLFOCUS, sent },
14051     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
14052     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
14053     { 0 }
14054 };
14055 
14056 static void test_SetForegroundWindow(void)
14057 {
14058     HWND hwnd;
14059 
14060     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
14061                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
14062                            100, 100, 200, 200, 0, 0, 0, NULL);
14063     ok (hwnd != 0, "Failed to create overlapped window\n");
14064     SetForegroundWindow( hwnd );
14065     flush_sequence();
14066 
14067     trace("SetForegroundWindow( 0 )\n");
14068     SetForegroundWindow( 0 );
14069     ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
14070     trace("SetForegroundWindow( GetDesktopWindow() )\n");
14071     SetForegroundWindow( GetDesktopWindow() );
14072     ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
14073                                         "foreground top level window", FALSE);
14074     trace("done\n");
14075 
14076     DestroyWindow(hwnd);
14077 }
14078 
14079 static DWORD get_input_codepage( void )
14080 {
14081     DWORD cp;
14082     int ret;
14083     HKL hkl = GetKeyboardLayout( 0 );
14084 
14085     ret = GetLocaleInfoW( LOWORD(hkl), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
14086                           (WCHAR *)&cp, sizeof(cp) / sizeof(WCHAR) );
14087     if (!ret) cp = CP_ACP;
14088     return cp;
14089 }
14090 
14091 static void test_dbcs_wm_char(void)
14092 {
14093     BYTE dbch[2];
14094     WCHAR wch, bad_wch;
14095     HWND hwnd, hwnd2;
14096     MSG msg;
14097     DWORD time;
14098     POINT pt;
14099     DWORD_PTR res;
14100     CPINFOEXA cpinfo;
14101     UINT i, j, k;
14102     struct message wmCharSeq[2];
14103     BOOL ret;
14104     DWORD cp = get_input_codepage();
14105 
14106     if (!pGetCPInfoExA)
14107     {
14108         win_skip("GetCPInfoExA is not available\n");
14109         return;
14110     }
14111 
14112     pGetCPInfoExA( cp, 0, &cpinfo );
14113     if (cpinfo.MaxCharSize != 2)
14114     {
14115         skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
14116         return;
14117     }
14118 
14119     dbch[0] = dbch[1] = 0;
14120     wch = 0;
14121     bad_wch = cpinfo.UnicodeDefaultChar;
14122     for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
14123         for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
14124             for (k = 128; k <= 255; k++)
14125             {
14126                 char str[2];
14127                 WCHAR wstr[2];
14128                 str[0] = j;
14129                 str[1] = k;
14130                 if (MultiByteToWideChar( cp, 0, str, 2, wstr, 2 ) == 1 &&
14131                     WideCharToMultiByte( cp, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
14132                     (BYTE)str[0] == j && (BYTE)str[1] == k &&
14133                     HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
14134                 {
14135                     dbch[0] = j;
14136                     dbch[1] = k;
14137                     wch = wstr[0];
14138                     break;
14139                 }
14140             }
14141 
14142     if (!wch)
14143     {
14144         skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
14145         return;
14146     }
14147     trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
14148            dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
14149 
14150     hwnd = CreateWindowExW(0, testWindowClassW, NULL,
14151                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
14152     hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
14153                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
14154     ok (hwnd != 0, "Failed to create overlapped window\n");
14155     ok (hwnd2 != 0, "Failed to create overlapped window\n");
14156     flush_sequence();
14157 
14158     memset( wmCharSeq, 0, sizeof(wmCharSeq) );
14159     wmCharSeq[0].message = WM_CHAR;
14160     wmCharSeq[0].flags = sent|wparam;
14161     wmCharSeq[0].wParam = wch;
14162 
14163     /* posted message */
14164     PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14165     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14166     ok( !ret, "got message %x\n", msg.message );
14167     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14168     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14169     ok( ret, "no message\n" );
14170     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14171     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
14172     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14173     ok( !ret, "got message %x\n", msg.message );
14174 
14175     /* posted thread message */
14176     PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
14177     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14178     ok( !ret, "got message %x\n", msg.message );
14179     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14180     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14181     ok( ret, "no message\n" );
14182     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14183     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
14184     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14185     ok( !ret, "got message %x\n", msg.message );
14186 
14187     /* sent message */
14188     flush_sequence();
14189     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14190     ok_sequence( WmEmptySeq, "no messages", FALSE );
14191     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14192     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14193     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14194     ok( !ret, "got message %x\n", msg.message );
14195 
14196     /* sent message with timeout */
14197     flush_sequence();
14198     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
14199     ok_sequence( WmEmptySeq, "no messages", FALSE );
14200     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
14201     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14202     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14203     ok( !ret, "got message %x\n", msg.message );
14204 
14205     /* sent message with timeout and callback */
14206     flush_sequence();
14207     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
14208     ok_sequence( WmEmptySeq, "no messages", FALSE );
14209     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
14210     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14211     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14212     ok( !ret, "got message %x\n", msg.message );
14213 
14214     /* sent message with callback */
14215     flush_sequence();
14216     SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14217     ok_sequence( WmEmptySeq, "no messages", FALSE );
14218     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
14219     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14220     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14221     ok( !ret, "got message %x\n", msg.message );
14222 
14223     /* direct window proc call */
14224     flush_sequence();
14225     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
14226     ok_sequence( WmEmptySeq, "no messages", FALSE );
14227     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
14228     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14229 
14230     /* dispatch message */
14231     msg.hwnd = hwnd;
14232     msg.message = WM_CHAR;
14233     msg.wParam = dbch[0];
14234     msg.lParam = 0;
14235     DispatchMessageA( &msg );
14236     ok_sequence( WmEmptySeq, "no messages", FALSE );
14237     msg.wParam = dbch[1];
14238     DispatchMessageA( &msg );
14239     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14240 
14241     /* window handle is irrelevant */
14242     flush_sequence();
14243     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
14244     ok_sequence( WmEmptySeq, "no messages", FALSE );
14245     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14246     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14247     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14248     ok( !ret, "got message %x\n", msg.message );
14249 
14250     /* interleaved post and send */
14251     flush_sequence();
14252     PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
14253     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
14254     ok_sequence( WmEmptySeq, "no messages", FALSE );
14255     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14256     ok( !ret, "got message %x\n", msg.message );
14257     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14258     ok_sequence( WmEmptySeq, "no messages", FALSE );
14259     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14260     ok( ret, "no message\n" );
14261     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14262     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
14263     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14264     ok( !ret, "got message %x\n", msg.message );
14265     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14266     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14267     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14268     ok( !ret, "got message %x\n", msg.message );
14269 
14270     /* interleaved sent message and winproc */
14271     flush_sequence();
14272     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14273     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
14274     ok_sequence( WmEmptySeq, "no messages", FALSE );
14275     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14276     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14277     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
14278     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14279 
14280     /* interleaved winproc and dispatch */
14281     msg.hwnd = hwnd;
14282     msg.message = WM_CHAR;
14283     msg.wParam = dbch[0];
14284     msg.lParam = 0;
14285     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
14286     DispatchMessageA( &msg );
14287     ok_sequence( WmEmptySeq, "no messages", FALSE );
14288     msg.wParam = dbch[1];
14289     DispatchMessageA( &msg );
14290     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14291     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
14292     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14293 
14294     /* interleaved sends */
14295     flush_sequence();
14296     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14297     SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
14298     ok_sequence( WmEmptySeq, "no messages", FALSE );
14299     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
14300     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14301     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14302     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14303 
14304     /* dbcs WM_CHAR */
14305     flush_sequence();
14306     SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
14307     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14308     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14309     ok( !ret, "got message %x\n", msg.message );
14310 
14311     /* other char messages are not magic */
14312     PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
14313     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14314     ok( ret, "no message\n" );
14315     ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
14316     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
14317     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14318     ok( !ret, "got message %x\n", msg.message );
14319     PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
14320     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14321     ok( ret, "no message\n" );
14322     ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
14323     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
14324     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14325     ok( !ret, "got message %x\n", msg.message );
14326 
14327     /* test retrieving messages */
14328 
14329     PostMessageW( hwnd, WM_CHAR, wch, 0 );
14330     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14331     ok( ret, "no message\n" );
14332     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14333     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14334     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14335     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14336     ok( ret, "no message\n" );
14337     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14338     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14339     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14340     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14341     ok( !ret, "got message %x\n", msg.message );
14342 
14343     /* message filters */
14344     PostMessageW( hwnd, WM_CHAR, wch, 0 );
14345     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14346     ok( ret, "no message\n" );
14347     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14348     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14349     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14350     /* message id is filtered, hwnd is not */
14351     ret = PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE );
14352     ok( !ret, "no message\n" );
14353     ret = PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE );
14354     ok( ret, "no message\n" );
14355     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14356     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14357     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14358     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14359     ok( !ret, "got message %x\n", msg.message );
14360 
14361     /* mixing GetMessage and PostMessage */
14362     PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
14363     ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
14364     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14365     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14366     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14367     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
14368     time = msg.time;
14369     pt = msg.pt;
14370     ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time );
14371     ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
14372     ok( ret, "no message\n" );
14373     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14374     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14375     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14376     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
14377     ok( msg.time == time, "bad time %x/%x\n", msg.time, time );
14378     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 );
14379     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14380     ok( !ret, "got message %x\n", msg.message );
14381 
14382     /* without PM_REMOVE */
14383     PostMessageW( hwnd, WM_CHAR, wch, 0 );
14384     ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
14385     ok( ret, "no message\n" );
14386     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14387     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14388     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14389     ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
14390     ok( ret, "no message\n" );
14391     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14392     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14393     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14394     ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
14395     ok( ret, "no message\n" );
14396     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14397     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14398     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14399     ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
14400     ok( ret, "no message\n" );
14401     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14402     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14403     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14404     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14405     ok( !ret, "got message %x\n", msg.message );
14406 
14407     DestroyWindow(hwnd);
14408     DestroyWindow(hwnd2);
14409 }
14410 
14411 static void test_unicode_wm_char(void)
14412 {
14413     HWND hwnd;
14414     MSG msg;
14415     struct message seq[2];
14416     HKL hkl_orig, hkl_greek;
14417     DWORD cp;
14418     LCID thread_locale;
14419 
14420     hkl_orig = GetKeyboardLayout( 0 );
14421     GetLocaleInfoW( LOWORD( hkl_orig ), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, (WCHAR*)&cp, sizeof(cp) / sizeof(WCHAR) );
14422     if (cp != 1252)
14423     {
14424         skip( "Default codepage %d\n", cp );
14425         return;
14426     }
14427 
14428     hkl_greek = LoadKeyboardLayoutA( "00000408", 0 );
14429     if (!hkl_greek || hkl_greek == hkl_orig /* win2k */)
14430     {
14431         skip( "Unable to load Greek keyboard layout\n" );
14432         return;
14433     }
14434 
14435     hwnd = CreateWindowExW( 0, testWindowClassW, NULL, WS_OVERLAPPEDWINDOW,
14436                             100, 100, 200, 200, 0, 0, 0, NULL );
14437     flush_sequence();
14438 
14439     PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
14440 
14441     while (GetMessageW( &msg, hwnd, 0, 0 ))
14442     {
14443         if (!ignore_message( msg.message )) break;
14444     }
14445 
14446     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14447     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14448     ok( msg.wParam == 0x3b1, "bad wparam %lx\n", msg.wParam );
14449     ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
14450 
14451     DispatchMessageW( &msg );
14452 
14453     memset( seq, 0, sizeof(seq) );
14454     seq[0].message = WM_CHAR;
14455     seq[0].flags = sent|wparam;
14456     seq[0].wParam = 0x3b1;
14457 
14458     ok_sequence( seq, "unicode WM_CHAR", FALSE );
14459 
14460     flush_sequence();
14461 
14462     /* greek alpha -> 'a' in cp1252 */
14463     PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
14464 
14465     ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
14466     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14467     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14468     ok( msg.wParam == 0x61, "bad wparam %lx\n", msg.wParam );
14469     ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
14470 
14471     DispatchMessageA( &msg );
14472 
14473     seq[0].wParam = 0x61;
14474     ok_sequence( seq, "unicode WM_CHAR", FALSE );
14475 
14476     thread_locale = GetThreadLocale();
14477     ActivateKeyboardLayout( hkl_greek, 0 );
14478     ok( GetThreadLocale() == thread_locale, "locale changed from %08x to %08x\n",
14479         thread_locale, GetThreadLocale() );
14480 
14481     flush_sequence();
14482 
14483     /* greek alpha -> 0xe1 in cp1253 */
14484     PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
14485 
14486     ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
14487     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14488     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14489     ok( msg.wParam == 0xe1, "bad wparam %lx\n", msg.wParam );
14490     ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
14491 
14492     DispatchMessageA( &msg );
14493 
14494     seq[0].wParam = 0x3b1;
14495     ok_sequence( seq, "unicode WM_CHAR", FALSE );
14496 
14497     DestroyWindow( hwnd );
14498     ActivateKeyboardLayout( hkl_orig, 0 );
14499     UnloadKeyboardLayout( hkl_greek );
14500 }
14501 
14502 #define ID_LISTBOX 0x000f
14503 
14504 static const struct message wm_lb_setcursel_0[] =
14505 {
14506     { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
14507     { WM_CTLCOLORLISTBOX, sent|parent },
14508     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
14509     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
14510     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
14511     { 0 }
14512 };
14513 static const struct message wm_lb_setcursel_1[] =
14514 {
14515     { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
14516     { WM_CTLCOLORLISTBOX, sent|parent },
14517     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
14518     { WM_CTLCOLORLISTBOX, sent|parent },
14519     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
14520     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
14521     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
14522     { 0 }
14523 };
14524 static const struct message wm_lb_setcursel_2[] =
14525 {
14526     { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
14527     { WM_CTLCOLORLISTBOX, sent|parent },
14528     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
14529     { WM_CTLCOLORLISTBOX, sent|parent },
14530     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
14531     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
14532     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
14533     { 0 }
14534 };
14535 static const struct message wm_lb_click_0[] =
14536 {
14537     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
14538     { HCBT_SETFOCUS, hook },
14539     { WM_KILLFOCUS, sent|parent },
14540     { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
14541     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
14542     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
14543     { WM_SETFOCUS, sent|defwinproc },
14544 
14545     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
14546     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
14547     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
14548     { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
14549     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
14550 
14551     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
14552     { WM_CTLCOLORLISTBOX, sent|parent },
14553     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
14554     { WM_CTLCOLORLISTBOX, sent|parent },
14555     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
14556     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
14557 
14558     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
14559     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
14560 
14561     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
14562     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
14563     { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
14564     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
14565     { 0 }
14566 };
14567 static const struct message wm_lb_deletestring[] =
14568 {
14569     { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
14570     { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
14571     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
14572     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
14573     { 0 }
14574 };
14575 static const struct message wm_lb_deletestring_reset[] =
14576 {
14577     { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
14578     { LB_RESETCONTENT, sent|wparam|lparam|defwinproc|optional, 0, 0 },
14579     { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
14580     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
14581     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
14582     { 0 }
14583 };
14584 static const struct message wm_lb_addstring[] =
14585 {
14586     { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef },
14587     { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed },
14588     { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee },
14589     { 0 }
14590 };
14591 static const struct message wm_lb_addstring_ownerdraw[] =
14592 {
14593     { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed },
14594     { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf0f2, 0xf30604ed },
14595     { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee },
14596     { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf1f2, 0xf30604ee },
14597     { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef },
14598     { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf2f2, 0xf30604ef },
14599     { 0 }
14600 };
14601 static const struct message wm_lb_addstring_sort_ownerdraw[] =
14602 {
14603     { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed },
14604     { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf0f2, 0xf30604ed },
14605     { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee },
14606     { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ed, 0xf30604ee },
14607     { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf1f2, 0xf30604ee },
14608     { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef },
14609     { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ed, 0xf30604ef },
14610     { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ee, 0xf30604ef },
14611     { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf2f2, 0xf30604ef },
14612     { 0 }
14613 };
14614 
14615 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
14616 
14617 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
14618 
14619 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
14620 {
14621     static LONG defwndproc_counter = 0;
14622     LRESULT ret;
14623     struct recvd_message msg;
14624 
14625     /* do not log painting messages */
14626     if (message != WM_PAINT &&
14627         message != WM_NCPAINT &&
14628         message != WM_SYNCPAINT &&
14629         message != WM_ERASEBKGND &&
14630         message != WM_NCHITTEST &&
14631         message != WM_GETTEXT &&
14632         !ignore_message( message ))
14633     {
14634         msg.hwnd = hwnd;
14635         msg.message = message;
14636         msg.flags = sent|wparam|lparam;
14637         if (defwndproc_counter) msg.flags |= defwinproc;
14638         msg.wParam = wp;
14639         if (message == LB_ADDSTRING)
14640             msg.lParam = lp ? hash_Ly((const char *)lp) : 0;
14641         else
14642             msg.lParam = lp;
14643         msg.descr = "listbox";
14644         add_message(&msg);
14645     }
14646 
14647     defwndproc_counter++;
14648     ret = CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
14649     defwndproc_counter--;
14650 
14651     return ret;
14652 }
14653 
14654 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
14655                                int caret_index, int top_index, int line)
14656 {
14657     LRESULT ret;
14658 
14659     /* calling an orig proc helps to avoid unnecessary message logging */
14660     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
14661     ok_(__FILE__, line)(ret == count, "expected count %d, got %ld\n", count, ret);
14662     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
14663     ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret);
14664     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
14665     ok_(__FILE__, line)(ret == caret_index ||
14666                         broken(cur_sel == -1 && caret_index == 0 && ret == -1),  /* nt4 */
14667                         "expected caret index %d, got %ld\n", caret_index, ret);
14668     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
14669     ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret);
14670 }
14671 
14672 static void test_listbox_messages(void)
14673 {
14674     HWND parent, listbox;
14675     LRESULT ret;
14676 
14677     parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW  | WS_VISIBLE,
14678                              100, 100, 200, 200, 0, 0, 0, NULL);
14679     /* with LBS_HASSTRINGS */
14680     listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
14681                               WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
14682                               10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
14683     listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
14684 
14685     check_lb_state(listbox, 0, LB_ERR, 0, 0);
14686 
14687     flush_sequence();
14688 
14689     log_all_parent_messages++;
14690 
14691     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
14692     ok(ret == 0, "expected 0, got %ld\n", ret);
14693     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
14694     ok(ret == 1, "expected 1, got %ld\n", ret);
14695     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
14696     ok(ret == 2, "expected 2, got %ld\n", ret);
14697 
14698     ok_sequence(wm_lb_addstring_ownerdraw, "LB_ADDSTRING", FALSE);
14699     check_lb_state(listbox, 3, LB_ERR, 0, 0);
14700 
14701     flush_sequence();
14702 
14703     trace("selecting item 0\n");
14704     ret = SendMessageA(listbox, LB_SETCURSEL, 0, 0);
14705     ok(ret == 0, "expected 0, got %ld\n", ret);
14706     ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
14707     check_lb_state(listbox, 3, 0, 0, 0);
14708     flush_sequence();
14709 
14710     trace("selecting item 1\n");
14711     ret = SendMessageA(listbox, LB_SETCURSEL, 1, 0);
14712     ok(ret == 1, "expected 1, got %ld\n", ret);
14713     ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
14714     check_lb_state(listbox, 3, 1, 1, 0);
14715 
14716     trace("selecting item 2\n");
14717     ret = SendMessageA(listbox, LB_SETCURSEL, 2, 0);
14718     ok(ret == 2, "expected 2, got %ld\n", ret);
14719     ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
14720     check_lb_state(listbox, 3, 2, 2, 0);
14721 
14722     trace("clicking on item 0\n");
14723     ret = SendMessageA(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
14724     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
14725     ret = SendMessageA(listbox, WM_LBUTTONUP, 0, 0);
14726     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
14727     ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
14728     check_lb_state(listbox, 3, 0, 0, 0);
14729     flush_sequence();
14730 
14731     trace("deleting item 0\n");
14732     ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14733     ok(ret == 2, "expected 2, got %ld\n", ret);
14734     ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
14735     check_lb_state(listbox, 2, -1, 0, 0);
14736     flush_sequence();
14737 
14738     trace("deleting item 0\n");
14739     ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14740     ok(ret == 1, "expected 1, got %ld\n", ret);
14741     ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
14742     check_lb_state(listbox, 1, -1, 0, 0);
14743     flush_sequence();
14744 
14745     trace("deleting item 0\n");
14746     ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14747     ok(ret == 0, "expected 0, got %ld\n", ret);
14748     ok_sequence(wm_lb_deletestring_reset, "LB_DELETESTRING 0", FALSE );
14749     check_lb_state(listbox, 0, -1, 0, 0);
14750     flush_sequence();
14751 
14752     trace("deleting item 0\n");
14753     ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14754     ok(ret == LB_ERR, "expected LB_ERR, got %ld\n", ret);
14755     check_lb_state(listbox, 0, -1, 0, 0);
14756     flush_sequence();
14757 
14758     log_all_parent_messages--;
14759 
14760     DestroyWindow(listbox);
14761 
14762     /* with LBS_SORT and without LBS_HASSTRINGS */
14763     listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
14764                               WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_SORT | WS_VISIBLE,
14765                               10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
14766     listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
14767 
14768     check_lb_state(listbox, 0, LB_ERR, 0, 0);
14769 
14770     flush_sequence();
14771 
14772     log_all_parent_messages++;
14773 
14774     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
14775     ok(ret == 0, "expected 0, got %ld\n", ret);
14776     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
14777     ok(ret == 1, "expected 1, got %ld\n", ret);
14778     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
14779     ok(ret == 2, "expected 2, got %ld\n", ret);
14780 
14781     ok_sequence(wm_lb_addstring_sort_ownerdraw, "LB_ADDSTRING", FALSE);
14782     check_lb_state(listbox, 3, LB_ERR, 0, 0);
14783 
14784     log_all_parent_messages--;
14785 
14786     DestroyWindow(listbox);
14787 
14788     /* with LBS_HASSTRINGS */
14789     listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
14790                               WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | WS_VISIBLE,
14791                               10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
14792     listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
14793 
14794     check_lb_state(listbox, 0, LB_ERR, 0, 0);
14795 
14796     flush_sequence();
14797 
14798     log_all_parent_messages++;
14799 
14800     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
14801     ok(ret == 0, "expected 0, got %ld\n", ret);
14802     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
14803     ok(ret == 1, "expected 1, got %ld\n", ret);
14804     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
14805     ok(ret == 2, "expected 2, got %ld\n", ret);
14806 
14807     ok_sequence(wm_lb_addstring, "LB_ADDSTRING", FALSE);
14808     check_lb_state(listbox, 3, LB_ERR, 0, 0);
14809 
14810     log_all_parent_messages--;
14811 
14812     DestroyWindow(listbox);
14813 
14814     /* with LBS_HASSTRINGS and LBS_SORT */
14815     listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
14816                               WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | LBS_SORT | WS_VISIBLE,
14817                               10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
14818     listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
14819 
14820     check_lb_state(listbox, 0, LB_ERR, 0, 0);
14821 
14822     flush_sequence();
14823 
14824     log_all_parent_messages++;
14825 
14826     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
14827     ok(ret == 0, "expected 0, got %ld\n", ret);
14828     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
14829     ok(ret == 0, "expected 0, got %ld\n", ret);
14830     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
14831     ok(ret == 1, "expected 1, got %ld\n", ret);
14832 
14833     ok_sequence(wm_lb_addstring, "LB_ADDSTRING", FALSE);
14834     check_lb_state(listbox, 3, LB_ERR, 0, 0);
14835 
14836     log_all_parent_messages--;
14837 
14838     DestroyWindow(listbox);
14839     DestroyWindow(parent);
14840 }
14841 
14842 /*************************** Menu test ******************************/
14843 static const struct message wm_popup_menu_1[] =
14844 {
14845     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
14846     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
14847     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0x20000001 },
14848     { WM_SYSKEYDOWN, sent|wparam|lparam, 'E', 0x20000001 },
14849     { WM_SYSCHAR, sent|wparam|lparam, 'e', 0x20000001 },
14850     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'e' },
14851     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
14852     { WM_INITMENU, sent|lparam, 0, 0 },
14853     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) },
14854     { WM_INITMENUPOPUP, sent|lparam, 0, 1 },
14855     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */
14856     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) },
14857     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 },
14858     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
14859     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001, 0, 0x40000000 },
14860     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */
14861     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
14862     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
14863     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
14864     { WM_MENUCOMMAND, sent }, /* |wparam, 200 - Win9x */
14865     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
14866     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
14867     { 0 }
14868 };
14869 static const struct message wm_popup_menu_2[] =
14870 {
14871     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
14872     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
14873     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
14874     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
14875     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
14876     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
14877     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
14878     { WM_INITMENU, sent|lparam, 0, 0 },
14879     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
14880     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
14881     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
14882     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
14883     { HCBT_CREATEWND, hook },
14884     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
14885                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
14886     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
14887     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
14888     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
14889     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
14890     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
14891     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
14892     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
14893     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
14894     { HCBT_DESTROYWND, hook },
14895     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
14896     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
14897     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
14898     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
14899     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
14900     { WM_MENUCOMMAND, sent }, /* |wparam, 100 - Win9x */
14901     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
14902     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
14903     { 0 }
14904 };
14905 static const struct message wm_popup_menu_3[] =
14906 {
14907     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
14908     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
14909     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
14910     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
14911     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
14912     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
14913     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
14914     { WM_INITMENU, sent|lparam, 0, 0 },
14915     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
14916     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
14917     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
14918     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
14919     { HCBT_CREATEWND, hook },
14920     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
14921                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
14922     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
14923     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
14924     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
14925     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
14926     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
14927     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
14928     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
14929     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
14930     { HCBT_DESTROYWND, hook },
14931     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
14932     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
14933     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
14934     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
14935     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
14936     { WM_COMMAND, sent|wparam|lparam, 100, 0 },
14937     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
14938     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
14939     { 0 }
14940 };
14941 
14942 static const struct message wm_single_menu_item[] =
14943 {
14944     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
14945     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
14946     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0x20000001 },
14947     { WM_SYSKEYDOWN, sent|wparam|lparam, 'Q', 0x20000001 },
14948     { WM_SYSCHAR, sent|wparam|lparam, 'q', 0x20000001 },
14949     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'q' },
14950     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
14951     { WM_INITMENU, sent|lparam, 0, 0 },
14952     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(300,MF_HILITE) },
14953     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
14954     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
14955     { WM_MENUCOMMAND, sent },
14956     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0xe0000001 },
14957     { WM_SYSKEYUP, sent|wparam|lparam, 'Q', 0xe0000001 },
14958     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 },
14959     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
14960 
14961     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 1 },
14962     { WM_KEYDOWN, sent|wparam|lparam, VK_ESCAPE, 1 },
14963     { WM_CHAR,  sent|wparam|lparam, VK_ESCAPE, 0x00000001 },
14964     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 },
14965     { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
14966     { 0 }
14967 };
14968 
14969 static LRESULT WINAPI parent_menu_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
14970 {
14971     if (message == WM_ENTERIDLE ||
14972         message == WM_INITMENU ||
14973         message == WM_INITMENUPOPUP ||
14974         message == WM_MENUSELECT ||
14975         message == WM_PARENTNOTIFY ||
14976         message == WM_ENTERMENULOOP ||
14977         message == WM_EXITMENULOOP ||
14978         message == WM_UNINITMENUPOPUP ||
14979         message == WM_KEYDOWN ||
14980         message == WM_KEYUP ||
14981         message == WM_CHAR ||
14982         message == WM_SYSKEYDOWN ||
14983         message == WM_SYSKEYUP ||
14984         message == WM_SYSCHAR ||
14985         message == WM_COMMAND ||
14986         message == WM_MENUCOMMAND)
14987     {
14988         struct recvd_message msg;
14989 
14990         msg.hwnd = hwnd;
14991         msg.message = message;
14992         msg.flags = sent|wparam|lparam;
14993         msg.wParam = wp;
14994         msg.lParam = lp;
14995         msg.descr = "parent_menu_proc";
14996         add_message(&msg);
14997     }
14998 
14999     return DefWindowProcA(hwnd, message, wp, lp);
15000 }
15001 
15002 static void set_menu_style(HMENU hmenu, DWORD style)
15003 {
15004     MENUINFO mi;
15005     BOOL ret;
15006 
15007     mi.cbSize = sizeof(mi);
15008     mi.fMask = MIM_STYLE;
15009     mi.dwStyle = style;
15010     SetLastError(0xdeadbeef);
15011     ret = pSetMenuInfo(hmenu, &mi);
15012     ok(ret, "SetMenuInfo error %u\n", GetLastError());
15013 }
15014 
15015 static DWORD get_menu_style(HMENU hmenu)
15016 {
15017     MENUINFO mi;
15018     BOOL ret;
15019 
15020     mi.cbSize = sizeof(mi);
15021     mi.fMask = MIM_STYLE;
15022     mi.dwStyle = 0;
15023     SetLastError(0xdeadbeef);
15024     ret = pGetMenuInfo(hmenu, &mi);
15025     ok(ret, "GetMenuInfo error %u\n", GetLastError());
15026 
15027     return mi.dwStyle;
15028 }
15029 
15030 static void test_menu_messages(void)
15031 {
15032     MSG msg;
15033     WNDCLASSA cls;
15034     HMENU hmenu, hmenu_popup;
15035     HWND hwnd;
15036     DWORD style;
15037 
15038     if (!pGetMenuInfo || !pSetMenuInfo)
15039     {
15040         win_skip("GetMenuInfo and/or SetMenuInfo are not available\n");
15041         return;
15042     }
15043     cls.style = 0;
15044     cls.lpfnWndProc = parent_menu_proc;
15045     cls.cbClsExtra = 0;
15046     cls.cbWndExtra = 0;
15047     cls.hInstance = GetModuleHandleA(0);
15048     cls.hIcon = 0;
15049     cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
15050     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
15051     cls.lpszMenuName = NULL;
15052     cls.lpszClassName = "TestMenuClass";
15053     UnregisterClassA(cls.lpszClassName, cls.hInstance);
15054     if (!RegisterClassA(&cls)) assert(0);
15055 
15056     SetLastError(0xdeadbeef);
15057     hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
15058                            100, 100, 200, 200, 0, 0, 0, NULL);
15059     ok(hwnd != 0, "LoadMenuA error %u\n", GetLastError());
15060 
15061     SetLastError(0xdeadbeef);
15062     hmenu = LoadMenuA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
15063     ok(hmenu != 0, "LoadMenuA error %u\n", GetLastError());
15064 
15065     SetMenu(hwnd, hmenu);
15066     SetForegroundWindow( hwnd );
15067     flush_events();
15068 
15069     set_menu_style(hmenu, MNS_NOTIFYBYPOS);
15070     style = get_menu_style(hmenu);
15071     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
15072 
15073     hmenu_popup = GetSubMenu(hmenu, 0);
15074     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
15075     style = get_menu_style(hmenu_popup);
15076     ok(style == 0, "expected 0, got %u\n", style);
15077 
15078     hmenu_popup = GetSubMenu(hmenu_popup, 0);
15079     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
15080     style = get_menu_style(hmenu_popup);
15081     ok(style == 0, "expected 0, got %u\n", style);
15082 
15083     /* Alt+E, Enter */
15084     trace("testing a popup menu command\n");
15085     flush_sequence();
15086     keybd_event(VK_MENU, 0, 0, 0);
15087     keybd_event('E', 0, 0, 0);
15088     keybd_event('E', 0, KEYEVENTF_KEYUP, 0);
15089     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
15090     keybd_event(VK_RETURN, 0, 0, 0);
15091     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
15092     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15093     {
15094         TranslateMessage(&msg);
15095         DispatchMessageA(&msg);
15096     }
15097     if (!sequence_cnt)  /* we didn't get any message */
15098     {
15099         skip( "queuing key events not supported\n" );
15100         goto done;
15101     }
15102     /* win98 queues only a WM_KEYUP and doesn't start menu tracking */
15103     if (sequence[0].message == WM_KEYUP && sequence[0].wParam == VK_MENU)
15104     {
15105         win_skip( "menu tracking through VK_MENU not supported\n" );
15106         goto done;
15107     }
15108     ok_sequence(wm_popup_menu_1, "popup menu command", FALSE);
15109 
15110     /* Alt+F, Right, Enter */
15111     trace("testing submenu of a popup menu command\n");
15112     flush_sequence();
15113     keybd_event(VK_MENU, 0, 0, 0);
15114     keybd_event('F', 0, 0, 0);
15115     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
15116     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
15117     keybd_event(VK_RIGHT, 0, 0, 0);
15118     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
15119     keybd_event(VK_RETURN, 0, 0, 0);
15120     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
15121     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15122     {
15123         TranslateMessage(&msg);
15124         DispatchMessageA(&msg);
15125     }
15126     ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE);
15127 
15128     trace("testing single menu item command\n");
15129     flush_sequence();
15130     keybd_event(VK_MENU, 0, 0, 0);
15131     keybd_event('Q', 0, 0, 0);
15132     keybd_event('Q', 0, KEYEVENTF_KEYUP, 0);
15133     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
15134     keybd_event(VK_ESCAPE, 0, 0, 0);
15135     keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
15136     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15137     {
15138         TranslateMessage(&msg);
15139         DispatchMessageA(&msg);
15140     }
15141     ok_sequence(wm_single_menu_item, "single menu item command", FALSE);
15142 
15143     set_menu_style(hmenu, 0);
15144     style = get_menu_style(hmenu);
15145     ok(style == 0, "expected 0, got %u\n", style);
15146 
15147     hmenu_popup = GetSubMenu(hmenu, 0);
15148     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
15149     set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS);
15150     style = get_menu_style(hmenu_popup);
15151     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
15152 
15153     hmenu_popup = GetSubMenu(hmenu_popup, 0);
15154     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
15155     style = get_menu_style(hmenu_popup);
15156     ok(style == 0, "expected 0, got %u\n", style);
15157 
15158     /* Alt+F, Right, Enter */
15159     trace("testing submenu of a popup menu command\n");
15160     flush_sequence();
15161     keybd_event(VK_MENU, 0, 0, 0);
15162     keybd_event('F', 0, 0, 0);
15163     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
15164     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
15165     keybd_event(VK_RIGHT, 0, 0, 0);
15166     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
15167     keybd_event(VK_RETURN, 0, 0, 0);
15168     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
15169     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15170     {
15171         TranslateMessage(&msg);
15172         DispatchMessageA(&msg);
15173     }
15174     ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE);
15175 
15176 done:
15177     DestroyWindow(hwnd);
15178     DestroyMenu(hmenu);
15179 }
15180 
15181 
15182 static void test_paintingloop(void)
15183 {
15184     HWND hwnd;
15185 
15186     paint_loop_done = FALSE;
15187     hwnd = CreateWindowExA(0x0,"PaintLoopWindowClass",
15188                                "PaintLoopWindowClass",WS_OVERLAPPEDWINDOW,
15189                                 100, 100, 100, 100, 0, 0, 0, NULL );
15190     ok(hwnd != 0, "PaintLoop window error %u\n", GetLastError());
15191     ShowWindow(hwnd,SW_NORMAL);
15192     SetFocus(hwnd);
15193 
15194     while (!paint_loop_done)
15195     {
15196         MSG msg;
15197         if (PeekMessageA(&msg, 0, 0, 0, 1))
15198         {
15199             TranslateMessage(&msg);
15200             DispatchMessageA(&msg);
15201         }
15202     }
15203     DestroyWindow(hwnd);
15204 }
15205 
15206 static const struct message NCRBUTTONDOWNSeq[] =
15207 {
15208     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
15209     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
15210     { WM_CAPTURECHANGED, sent },
15211     { WM_CONTEXTMENU, sent, /*hwnd*/0, -1 },
15212     { 0 }
15213 };
15214 
15215 static const struct message NCXBUTTONUPSeq1[] =
15216 {
15217     { WM_APPCOMMAND, sent|lparam, /*hwnd*/0, MAKELPARAM(0, FAPPCOMMAND_MOUSE | APPCOMMAND_BROWSER_BACKWARD) },
15218     { 0 }
15219 };
15220 
15221 static const struct message NCXBUTTONUPSeq2[] =
15222 {
15223     { WM_APPCOMMAND, sent|lparam, /*hwnd*/0, MAKELPARAM(0, FAPPCOMMAND_MOUSE | APPCOMMAND_BROWSER_FORWARD) },
15224     { 0 }
15225 };
15226 
15227 struct rbuttonup_thread_data
15228 {
15229     HWND hwnd;
15230     HANDLE wndproc_finished;
15231 };
15232 
15233 static DWORD CALLBACK post_rbuttonup_msg( void *arg )
15234 {
15235     struct rbuttonup_thread_data *data = arg;
15236     DWORD ret;
15237 
15238     ret = WaitForSingleObject( data->wndproc_finished, 500 );
15239     todo_wine ok( ret == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", ret );
15240     if( ret == WAIT_OBJECT_0 ) return 0;
15241 
15242     PostMessageA( data->hwnd, WM_RBUTTONUP, 0, 0 );
15243     return 0;
15244 }
15245 
15246 static void test_defwinproc(void)
15247 {
15248     HWND hwnd;
15249     MSG msg;
15250     BOOL gotwmquit = FALSE;
15251     POINT pos;
15252     RECT rect;
15253     INT x, y;
15254     LRESULT res;
15255     struct rbuttonup_thread_data data;
15256     char buffA[64];
15257     HANDLE thread;
15258 
15259     hwnd = CreateWindowExA(0, "TestWindowClass", "test_defwndproc",
15260             WS_VISIBLE | WS_CAPTION | WS_OVERLAPPEDWINDOW, 0,0,500,100,0,0,0, NULL);
15261     assert(hwnd);
15262     flush_events();
15263 
15264     buffA[0] = 0;
15265     GetWindowTextA(hwnd, buffA, sizeof(buffA)/sizeof(*buffA));
15266     ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
15267 
15268     /* Zero high word of the lParam */
15269     res = DefWindowProcA(hwnd, WM_SETTEXT, 0, 0x1234);
15270     ok(res == 0, "WM_SETTEXT was expected to fail, %ld\n", res);
15271 
15272     GetWindowTextA(hwnd, buffA, sizeof(buffA)/sizeof(*buffA));
15273     ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
15274 
15275     res = DefWindowProcW(hwnd, WM_SETTEXT, 0, 0x1234);
15276     ok(res == 0, "WM_SETTEXT was expected to fail, %ld\n", res);
15277 
15278     GetWindowTextA(hwnd, buffA, sizeof(buffA)/sizeof(*buffA));
15279     ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
15280 
15281     GetCursorPos(&pos);
15282     GetWindowRect(hwnd, &rect);
15283     x = (rect.left+rect.right) / 2;
15284     y = rect.top + GetSystemMetrics(SM_CYFRAME) + 1;
15285     SetCursorPos(x, y);
15286     flush_events();
15287     res = DefWindowProcA( hwnd, WM_NCHITTEST, 0, MAKELPARAM(x, y));
15288     ok(res == HTCAPTION, "WM_NCHITTEST returned %ld\n", res);
15289 
15290     mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 );
15291     mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 );
15292     flush_events();
15293 
15294     flush_sequence();
15295     mouse_event( MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0 );
15296     /* workaround for missing support for clicking on window frame */
15297     data.hwnd = hwnd;
15298     data.wndproc_finished = CreateEventA( NULL, FALSE, FALSE, NULL );
15299     thread = CreateThread( NULL, 0, post_rbuttonup_msg, (void*)&data, 0, NULL );
15300 
15301     DefWindowProcA( hwnd, WM_NCRBUTTONDOWN, HTCAPTION, MAKELPARAM(x, y));
15302     ok_sequence(NCRBUTTONDOWNSeq, "WM_NCRBUTTONDOWN on caption", FALSE);
15303 
15304     res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, 0, MAKELPARAM(x, y));
15305     ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15306     ok_sequence(WmEmptySeq, "WM_NCXBUTTONUP without button", FALSE);
15307 
15308     res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, XBUTTON1), MAKELPARAM(x, y));
15309     ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15310     ok_sequence(NCXBUTTONUPSeq1, "WM_NCXBUTTONUP with XBUTTON1", FALSE);
15311 
15312     res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, XBUTTON2), MAKELPARAM(x, y));
15313     ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15314     ok_sequence(NCXBUTTONUPSeq2, "WM_NCXBUTTONUP with XBUTTON2", FALSE);
15315 
15316     res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, 3), MAKELPARAM(x, y));
15317     ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15318     ok_sequence(WmEmptySeq, "WM_NCXBUTTONUP with invalid button", FALSE);
15319 
15320     SetEvent( data.wndproc_finished );
15321     WaitForSingleObject( thread, 1000 );
15322     CloseHandle( data.wndproc_finished );
15323     CloseHandle( thread );
15324 
15325     SetCursorPos(pos.x, pos.y);
15326 
15327     DefWindowProcA( hwnd, WM_ENDSESSION, 1, 0);
15328     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) {
15329         if( msg.message == WM_QUIT) gotwmquit = TRUE;
15330         DispatchMessageA( &msg );
15331     }
15332     ok(!gotwmquit, "Unexpected WM_QUIT message!\n");
15333     DestroyWindow( hwnd);
15334 }
15335 
15336 #define clear_clipboard(hwnd)  clear_clipboard_(__LINE__, (hwnd))
15337 static void clear_clipboard_(int line, HWND hWnd)
15338 {
15339     BOOL succ;
15340     succ = OpenClipboard(hWnd);
15341     ok_(__FILE__, line)(succ, "OpenClipboard failed, err=%u\n", GetLastError());
15342     succ = EmptyClipboard();
15343     ok_(__FILE__, line)(succ, "EmptyClipboard failed, err=%u\n", GetLastError());
15344     succ = CloseClipboard();
15345     ok_(__FILE__, line)(succ, "CloseClipboard failed, err=%u\n", GetLastError());
15346 }
15347 
15348 #define expect_HWND(expected, got) expect_HWND_(__LINE__, (expected), (got))
15349 static void expect_HWND_(int line, HWND expected, HWND got)
15350 {
15351     ok_(__FILE__, line)(got==expected, "Expected %p, got %p\n", expected, got);
15352 }
15353 
15354 static WNDPROC pOldViewerProc;
15355 
15356 static LRESULT CALLBACK recursive_viewer_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
15357 {
15358     static BOOL recursion_guard;
15359 
15360     if (message == WM_DRAWCLIPBOARD && !recursion_guard)
15361     {
15362         recursion_guard = TRUE;
15363         clear_clipboard(hWnd);
15364         recursion_guard = FALSE;
15365     }
15366     return CallWindowProcA(pOldViewerProc, hWnd, message, wParam, lParam);
15367 }
15368 
15369 static void test_clipboard_viewers(void)
15370 {
15371     static struct message wm_change_cb_chain[] =
15372     {
15373         { WM_CHANGECBCHAIN, sent|wparam|lparam, 0, 0 },
15374         { 0 }
15375     };
15376     static const struct message wm_clipboard_destroyed[] =
15377     {
15378         { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
15379         { 0 }
15380     };
15381     static struct message wm_clipboard_changed[] =
15382     {
15383         { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
15384         { 0 }
15385     };
15386     static struct message wm_clipboard_changed_and_owned[] =
15387     {
15388         { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
15389         { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
15390         { 0 }
15391     };
15392 
15393     HINSTANCE hInst = GetModuleHandleA(NULL);
15394     HWND hWnd1, hWnd2, hWnd3;
15395     HWND hOrigViewer;
15396     HWND hRet;
15397 
15398     hWnd1 = CreateWindowExA(0, "TestWindowClass", "Clipboard viewer test wnd 1",
15399         WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
15400         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
15401         GetDesktopWindow(), NULL, hInst, NULL);
15402     hWnd2 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 2",
15403         WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
15404         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
15405         GetDesktopWindow(), NULL, hInst, NULL);
15406     hWnd3 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 3",
15407         WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
15408         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
15409         GetDesktopWindow(), NULL, hInst, NULL);
15410     trace("clipbd viewers: hWnd1=%p, hWnd2=%p, hWnd3=%p\n", hWnd1, hWnd2, hWnd3);
15411     assert(hWnd1 && hWnd2 && hWnd3);
15412 
15413     CountClipboardFormats(); /* Ensure that we do not have an X11 update to the clipboard */
15414     flush_sequence();
15415 
15416     /* Test getting the clipboard viewer and setting the viewer to NULL. */
15417     hOrigViewer = GetClipboardViewer();
15418     hRet = SetClipboardViewer(NULL);
15419     ok_sequence(WmEmptySeq, "set viewer to NULL", FALSE);
15420     expect_HWND(hOrigViewer, hRet);
15421     expect_HWND(NULL, GetClipboardViewer());
15422 
15423     /* Test registering hWnd1 as a viewer. */
15424     hRet = SetClipboardViewer(hWnd1);
15425     wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
15426     ok_sequence(wm_clipboard_changed, "set viewer NULL->1", FALSE);
15427     expect_HWND(NULL, hRet);
15428     expect_HWND(hWnd1, GetClipboardViewer());
15429 
15430     /* Test that changing the clipboard actually refreshes the registered viewer. */
15431     clear_clipboard(hWnd1);
15432     wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
15433     ok_sequence(wm_clipboard_changed, "clear clipbd (viewer=owner=1)", FALSE);
15434 
15435     /* Again, but with different owner. */
15436     clear_clipboard(hWnd2);
15437     wm_clipboard_changed_and_owned[1].wParam = (WPARAM) GetClipboardOwner();
15438     ok_sequence(wm_clipboard_changed_and_owned, "clear clipbd (viewer=1, owner=2)", FALSE);
15439 
15440     /* Test re-registering same window. */
15441     hRet = SetClipboardViewer(hWnd1);
15442     wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
15443     ok_sequence(wm_clipboard_changed, "set viewer 1->1", FALSE);
15444     expect_HWND(hWnd1, hRet);
15445     expect_HWND(hWnd1, GetClipboardViewer());
15446 
15447     /* Test ChangeClipboardChain. */
15448     ChangeClipboardChain(hWnd2, hWnd3);
15449     wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
15450     wm_change_cb_chain[0].lParam = (LPARAM) hWnd3;
15451     ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=3)", FALSE);
15452     expect_HWND(hWnd1, GetClipboardViewer());
15453 
15454     ChangeClipboardChain(hWnd2, NULL);
15455     wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
15456     wm_change_cb_chain[0].lParam = 0;
15457     ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=NULL)", FALSE);
15458     expect_HWND(hWnd1, GetClipboardViewer());
15459 
15460     ChangeClipboardChain(NULL, hWnd2);
15461     ok_sequence(WmEmptySeq, "change chain (viewer=1, remove=NULL, next=2)", FALSE);
15462     expect_HWND(hWnd1, GetClipboardViewer());
15463 
15464     /* Actually change clipboard viewer with ChangeClipboardChain. */
15465     ChangeClipboardChain(hWnd1, hWnd2);
15466     ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=2)", FALSE);
15467     expect_HWND(hWnd2, GetClipboardViewer());
15468 
15469     /* Test that no refresh messages are sent when viewer has unregistered. */
15470     clear_clipboard(hWnd2);
15471     ok_sequence(WmEmptySeq, "clear clipd (viewer=2, owner=1)", FALSE);
15472 
15473     /* Register hWnd1 again. */
15474     ChangeClipboardChain(hWnd2, hWnd1);
15475     ok_sequence(WmEmptySeq, "change chain (viewer=remove=2, next=1)", FALSE);
15476     expect_HWND(hWnd1, GetClipboardViewer());
15477 
15478     /* Subclass hWnd1 so that when it receives a WM_DRAWCLIPBOARD message, it
15479      * changes the clipboard. When this happens, the system shouldn't send
15480      * another WM_DRAWCLIPBOARD (as this could cause an infinite loop).
15481      */
15482     pOldViewerProc = (WNDPROC) SetWindowLongPtrA(hWnd1, GWLP_WNDPROC, (LONG_PTR) recursive_viewer_proc);
15483     clear_clipboard(hWnd2);
15484     /* The clipboard owner is changed in recursive_viewer_proc: */
15485     wm_clipboard_changed[0].wParam = (WPARAM) hWnd2;
15486     ok_sequence(wm_clipboard_changed, "recursive clear clipbd (viewer=1, owner=2)", TRUE);
15487 
15488     /* Test unregistering. */
15489     ChangeClipboardChain(hWnd1, NULL);
15490     ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=NULL)", FALSE);
15491     expect_HWND(NULL, GetClipboardViewer());
15492 
15493     clear_clipboard(hWnd1);
15494     ok_sequence(wm_clipboard_destroyed, "clear clipbd (no viewer, owner=1)", FALSE);
15495 
15496     DestroyWindow(hWnd1);
15497     DestroyWindow(hWnd2);
15498     DestroyWindow(hWnd3);
15499     SetClipboardViewer(hOrigViewer);
15500 }
15501 
15502 static void test_PostMessage(void)
15503 {
15504     static const struct
15505     {
15506         HWND hwnd;
15507         BOOL ret;
15508     } data[] =
15509     {
15510         { HWND_TOP /* 0 */, TRUE },
15511         { HWND_BROADCAST, TRUE },
15512         { HWND_BOTTOM, TRUE },
15513         { HWND_TOPMOST, TRUE },
15514         { HWND_NOTOPMOST, FALSE },
15515         { HWND_MESSAGE, FALSE },
15516         { (HWND)0xdeadbeef, FALSE }
15517     };
15518     int i;
15519     HWND hwnd;
15520     BOOL ret;
15521     MSG msg;
15522     static const WCHAR staticW[] = {'s','t','a','t','i','c',0};
15523 
15524     SetLastError(0xdeadbeef);
15525     hwnd = CreateWindowExW(0, staticW, NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
15526     if (!hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
15527     {
15528         win_skip("Skipping some PostMessage tests on Win9x/WinMe\n");
15529         return;
15530     }
15531     assert(hwnd);
15532 
15533     flush_events();
15534 
15535     PostMessageA(hwnd, WM_USER+1, 0x1234, 0x5678);
15536     PostMessageA(0, WM_USER+2, 0x5678, 0x1234);
15537 
15538     for (i = 0; i < sizeof(data)/sizeof(data[0]); i++)
15539     {
15540         memset(&msg, 0xab, sizeof(msg));
15541         ret = PeekMessageA(&msg, data[i].hwnd, 0, 0, PM_NOREMOVE);
15542         ok(ret == data[i].ret, "%d: hwnd %p expected %d, got %d\n", i, data[i].hwnd, data[i].ret, ret);
15543         if (data[i].ret)
15544         {
15545             if (data[i].hwnd)
15546                 ok(ret && msg.hwnd == 0 && msg.message == WM_USER+2 &&
15547                    msg.wParam == 0x5678 && msg.lParam == 0x1234,
15548                    "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/0/WM_USER+2/0x5678/0x1234\n",
15549                    i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam);
15550             else
15551                 ok(ret && msg.hwnd == hwnd && msg.message == WM_USER+1 &&
15552                    msg.wParam == 0x1234 && msg.lParam == 0x5678,
15553                    "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/%p/WM_USER+1/0x1234/0x5678\n",
15554                    i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam, msg.hwnd);
15555         }
15556     }
15557 
15558     DestroyWindow(hwnd);
15559     flush_events();
15560 }
15561 
15562 static LPARAM g_broadcast_lparam;
15563 static LRESULT WINAPI broadcast_test_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
15564 {
15565     WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
15566 
15567     if (wParam == 0xbaadbeef)
15568         g_broadcast_lparam = wParam;
15569     else
15570         g_broadcast_lparam = 0;
15571 
15572     return CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
15573 }
15574 
15575 static void test_broadcast(void)
15576 {
15577     static const UINT messages[] =
15578     {
15579         WM_USER-1,
15580         WM_USER,
15581         WM_USER+1,
15582         0xc000-1,
15583         0xc000, /* lowest possible atom returned by RegisterWindowMessage */
15584         0xffff,
15585     };
15586     WNDPROC oldproc;
15587     unsigned int i;
15588     HWND hwnd;
15589 
15590     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, NULL);
15591     ok(hwnd != NULL, "got %p\n", hwnd);
15592 
15593     oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)broadcast_test_proc);
15594     SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
15595 
15596     for (i = 0; i < sizeof(messages)/sizeof(messages[0]); i++)
15597     {
15598         BOOL ret;
15599         MSG msg;
15600 
15601         flush_events();
15602         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15603             ;
15604 
15605         /* post, broadcast */
15606         ret = PostMessageA(HWND_BROADCAST, messages[i], 0, 0);
15607         ok(ret, "%d: got %d, error %d\n", i, ret, GetLastError());
15608 
15609         memset(&msg, 0xab, sizeof(msg));
15610         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
15611         if (messages[i] < WM_USER || messages[i] >= 0xc000)
15612         {
15613             ok(ret, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError());
15614             ok(msg.hwnd == hwnd, "%d: got %p\n", i, msg.hwnd);
15615         }
15616         else
15617         {
15618             ok(!ret, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError());
15619         }
15620 
15621         /* post, topmost */
15622         ret = PostMessageA(HWND_TOPMOST, messages[i], 0, 0);
15623         ok(ret, "%d: got %d, error %d\n", i, ret, GetLastError());
15624 
15625         memset(&msg, 0xab, sizeof(msg));
15626         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
15627         if (messages[i] < WM_USER || messages[i] >= 0xc000)
15628         {
15629             ok(ret, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError());
15630             ok(msg.hwnd == hwnd, "%d: got %p\n", i, msg.hwnd);
15631         }
15632         else
15633         {
15634             ok(!ret, "%d: got %d, error %d\n", i, ret, GetLastError());
15635         }
15636 
15637         /* send, broadcast */
15638         g_broadcast_lparam = 0xdead;
15639         ret = SendMessageTimeoutA(HWND_BROADCAST, messages[i], 0xbaadbeef, 0, SMTO_NORMAL, 2000, NULL);
15640         if (!ret && GetLastError() == ERROR_TIMEOUT)
15641             win_skip("broadcasting test %d, timeout\n", i);
15642         else
15643         {
15644             if (messages[i] < WM_USER || messages[i] >= 0xc000)
15645             {
15646                 ok(g_broadcast_lparam == 0xbaadbeef, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
15647                     g_broadcast_lparam, GetLastError());
15648             }
15649             else
15650             {
15651                 ok(g_broadcast_lparam == 0xdead, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
15652                     g_broadcast_lparam, GetLastError());
15653             }
15654         }
15655 
15656         /* send, topmost */
15657         g_broadcast_lparam = 0xdead;
15658         ret = SendMessageTimeoutA(HWND_TOPMOST, messages[i], 0xbaadbeef, 0, SMTO_NORMAL, 2000, NULL);
15659         if (!ret && GetLastError() == ERROR_TIMEOUT)
15660             win_skip("broadcasting test %d, timeout\n", i);
15661         else
15662         {
15663             if (messages[i] < WM_USER || messages[i] >= 0xc000)
15664             {
15665                 ok(g_broadcast_lparam == 0xbaadbeef, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
15666                     g_broadcast_lparam, GetLastError());
15667             }
15668             else
15669             {
15670                 ok(g_broadcast_lparam == 0xdead, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
15671                     g_broadcast_lparam, GetLastError());
15672             }
15673         }
15674     }
15675 
15676     DestroyWindow(hwnd);
15677 }
15678 
15679 static const struct
15680 {
15681     DWORD exp, broken;
15682     BOOL todo;
15683 } wait_idle_expect[] =
15684 {
15685 /* 0 */  { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
15686          { WAIT_TIMEOUT, 0,            FALSE },
15687          { WAIT_TIMEOUT, 0,            FALSE },
15688          { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
15689          { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
15690 /* 5 */  { WAIT_TIMEOUT, 0,            FALSE },
15691          { WAIT_TIMEOUT, 0,            FALSE },
15692          { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
15693          { 0,            0,            FALSE },
15694          { 0,            0,            FALSE },
15695 /* 10 */ { 0,            0,            FALSE },
15696          { 0,            0,            FALSE },
15697          { 0,            WAIT_TIMEOUT, FALSE },
15698          { 0,            0,            FALSE },
15699          { 0,            0,            FALSE },
15700 /* 15 */ { 0,            0,            FALSE },
15701          { WAIT_TIMEOUT, 0,            FALSE },
15702          { WAIT_TIMEOUT, 0,            FALSE },
15703          { WAIT_TIMEOUT, 0,            FALSE },
15704          { WAIT_TIMEOUT, 0,            FALSE },
15705 /* 20 */ { WAIT_TIMEOUT, 0,            FALSE },
15706 };
15707 
15708 static DWORD CALLBACK do_wait_idle_child_thread( void *arg )
15709 {
15710     MSG msg;
15711 
15712     PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
15713     Sleep( 200 );
15714     MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
15715     return 0;
15716 }
15717 
15718 static void do_wait_idle_child( int arg )
15719 {
15720     WNDCLASSA cls;
15721     MSG msg;
15722     HWND hwnd = 0;
15723     HANDLE thread;
15724     DWORD id;
15725     HANDLE start_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_start" );
15726     HANDLE end_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_end" );
15727 
15728     memset( &cls, 0, sizeof(cls) );
15729     cls.lpfnWndProc   = DefWindowProcA;
15730     cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
15731     cls.hCursor       = LoadCursorA(0, (LPCSTR)IDC_ARROW);
15732     cls.lpszClassName = "TestClass";
15733     RegisterClassA( &cls );
15734 
15735     PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );  /* create the msg queue */
15736 
15737     ok( start_event != 0, "failed to create start event, error %u\n", GetLastError() );
15738     ok( end_event != 0, "failed to create end event, error %u\n", GetLastError() );
15739 
15740     switch (arg)
15741     {
15742     case 0:
15743         SetEvent( start_event );
15744         break;
15745     case 1:
15746         SetEvent( start_event );
15747         Sleep( 200 );
15748         PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
15749         break;
15750     case 2:
15751         SetEvent( start_event );
15752         Sleep( 200 );
15753         PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
15754         PostThreadMessageA( GetCurrentThreadId(), WM_COMMAND, 0x1234, 0xabcd );
15755         PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
15756         break;
15757     case 3:
15758         SetEvent( start_event );
15759         Sleep( 200 );
15760         SendMessageA( HWND_BROADCAST, WM_WININICHANGE, 0, 0 );
15761         break;
15762     case 4:
15763         SetEvent( start_event );
15764         Sleep( 200 );
15765         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
15766         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
15767         break;
15768     case 5:
15769         SetEvent( start_event );
15770         Sleep( 200 );
15771         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
15772         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
15773         break;
15774     case 6:
15775         SetEvent( start_event );
15776         Sleep( 200 );
15777         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
15778         while (PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ))
15779         {
15780             GetMessageA( &msg, 0, 0, 0 );
15781             DispatchMessageA( &msg );
15782         }
15783         break;
15784     case 7:
15785         SetEvent( start_event );
15786         Sleep( 200 );
15787         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
15788         SetTimer( hwnd, 3, 1, NULL );
15789         Sleep( 200 );
15790         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
15791         break;
15792     case 8:
15793         SetEvent( start_event );
15794         Sleep( 200 );
15795         PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
15796         MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
15797         break;
15798     case 9:
15799         SetEvent( start_event );
15800         Sleep( 200 );
15801         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
15802         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
15803         for (;;) GetMessageA( &msg, 0, 0, 0 );
15804         break;
15805     case 10:
15806         SetEvent( start_event );
15807         Sleep( 200 );
15808         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
15809         SetTimer( hwnd, 3, 1, NULL );
15810         Sleep( 200 );
15811         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
15812         break;
15813     case 11:
15814         SetEvent( start_event );
15815         Sleep( 200 );
15816         return;  /* exiting the process makes WaitForInputIdle return success too */
15817     case 12:
15818         PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
15819         Sleep( 200 );
15820         MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
15821         SetEvent( start_event );
15822         break;
15823     case 13:
15824         SetEvent( start_event );
15825         PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
15826         Sleep( 200 );
15827         thread = CreateThread( NULL, 0, do_wait_idle_child_thread, NULL, 0, &id );
15828         WaitForSingleObject( thread, 10000 );
15829         CloseHandle( thread );
15830         break;
15831     case 14:
15832         SetEvent( start_event );
15833         Sleep( 200 );
15834         PeekMessageA( &msg, HWND_TOPMOST, 0, 0, PM_NOREMOVE );
15835         break;
15836     case 15:
15837         SetEvent( start_event );
15838         Sleep( 200 );
15839         PeekMessageA( &msg, HWND_BROADCAST, 0, 0, PM_NOREMOVE );
15840         break;
15841     case 16:
15842         SetEvent( start_event );
15843         Sleep( 200 );
15844         PeekMessageA( &msg, HWND_BOTTOM, 0, 0, PM_NOREMOVE );
15845         break;
15846     case 17:
15847         SetEvent( start_event );
15848         Sleep( 200 );
15849         PeekMessageA( &msg, (HWND)0xdeadbeef, 0, 0, PM_NOREMOVE );
15850         break;
15851     case 18:
15852         SetEvent( start_event );
15853         Sleep( 200 );
15854         PeekMessageA( &msg, HWND_NOTOPMOST, 0, 0, PM_NOREMOVE );
15855         break;
15856     case 19:
15857         SetEvent( start_event );
15858         Sleep( 200 );
15859         PeekMessageA( &msg, HWND_MESSAGE, 0, 0, PM_NOREMOVE );
15860         break;
15861     case 20:
15862         SetEvent( start_event );
15863         Sleep( 200 );
15864         PeekMessageA( &msg, GetDesktopWindow(), 0, 0, PM_NOREMOVE );
15865         break;
15866     }
15867     WaitForSingleObject( end_event, 2000 );
15868     CloseHandle( start_event );
15869     CloseHandle( end_event );
15870     if (hwnd) DestroyWindow( hwnd );
15871 }
15872 
15873 static LRESULT CALLBACK wait_idle_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
15874 {
15875     if (msg == WM_WININICHANGE) Sleep( 200 );  /* make sure the child waits */
15876     return DefWindowProcA( hwnd, msg, wp, lp );
15877 }
15878 
15879 static DWORD CALLBACK wait_idle_thread( void *arg )
15880 {
15881     WNDCLASSA cls;
15882     MSG msg;
15883     HWND hwnd;
15884 
15885     memset( &cls, 0, sizeof(cls) );
15886     cls.lpfnWndProc   = wait_idle_proc;
15887     cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
15888     cls.hCursor       = LoadCursorA(0, (LPCSTR)IDC_ARROW);
15889     cls.lpszClassName = "TestClass";
15890     RegisterClassA( &cls );
15891 
15892     hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL);
15893     while (GetMessageA( &msg, 0, 0, 0 )) DispatchMessageA( &msg );
15894     DestroyWindow(hwnd);
15895     return 0;
15896 }
15897 
15898 static void test_WaitForInputIdle( char *argv0 )
15899 {
15900     char path[MAX_PATH];
15901     PROCESS_INFORMATION pi;
15902     STARTUPINFOA startup;
15903     BOOL ret;
15904     HANDLE start_event, end_event, thread;
15905     unsigned int i;
15906     DWORD id;
15907     const IMAGE_DOS_HEADER *dos = (const IMAGE_DOS_HEADER *)GetModuleHandleA(0);
15908     const IMAGE_NT_HEADERS *nt = (const IMAGE_NT_HEADERS *)((const char *)dos + dos->e_lfanew);
15909     BOOL console_app = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_GUI);
15910 
15911     if (console_app)  /* build the test with -mwindows for better coverage */
15912         trace( "not built as a GUI app, WaitForInputIdle may not be fully tested\n" );
15913 
15914     start_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_start");
15915     end_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_end");
15916     ok(start_event != 0, "failed to create start event, error %u\n", GetLastError());
15917     ok(end_event != 0, "failed to create end event, error %u\n", GetLastError());
15918 
15919     memset( &startup, 0, sizeof(startup) );
15920     startup.cb = sizeof(startup);
15921     startup.dwFlags = STARTF_USESHOWWINDOW;
15922     startup.wShowWindow = SW_SHOWNORMAL;
15923 
15924     thread = CreateThread( NULL, 0, wait_idle_thread, NULL, 0, &id );
15925 
15926     for (i = 0; i < sizeof(wait_idle_expect)/sizeof(wait_idle_expect[0]); i++)
15927     {
15928         ResetEvent( start_event );
15929         ResetEvent( end_event );
15930 #ifndef __REACTOS__
15931         sprintf( path, "%s msg %u", argv0, i );
15932 #else
15933         sprintf( path, "%s msg_queue %u", argv0, i );
15934 #endif
15935         ret = CreateProcessA( NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &pi );
15936         ok( ret, "CreateProcess '%s' failed err %u.\n", path, GetLastError() );
15937         if (ret)
15938         {
15939             ret = WaitForSingleObject( start_event, 5000 );
15940             ok( ret == WAIT_OBJECT_0, "%u: WaitForSingleObject failed\n", i );
15941             if (ret == WAIT_OBJECT_0)
15942             {
15943                 ret = WaitForInputIdle( pi.hProcess, 1000 );
15944                 if (ret == WAIT_FAILED)
15945                     ok( console_app ||
15946                         ret == wait_idle_expect[i].exp ||
15947                         broken(ret == wait_idle_expect[i].broken),
15948                         "%u: WaitForInputIdle error %08x expected %08x\n",
15949                         i, ret, wait_idle_expect[i].exp );
15950                 else todo_wine_if (wait_idle_expect[i].todo)
15951                     ok( ret == wait_idle_expect[i].exp || broken(ret == wait_idle_expect[i].broken),
15952                         "%u: WaitForInputIdle error %08x expected %08x\n",
15953                         i, ret, wait_idle_expect[i].exp );
15954                 SetEvent( end_event );
15955                 WaitForSingleObject( pi.hProcess, 1000 );  /* give it a chance to exit on its own */
15956             }
15957             TerminateProcess( pi.hProcess, 0 );  /* just in case */
15958             winetest_wait_child_process( pi.hProcess );
15959             ret = WaitForInputIdle( pi.hProcess, 100 );
15960             ok( ret == WAIT_FAILED, "%u: WaitForInputIdle after exit error %08x\n", i, ret );
15961             CloseHandle( pi.hProcess );
15962             CloseHandle( pi.hThread );
15963         }
15964     }
15965     CloseHandle( start_event );
15966     PostThreadMessageA( id, WM_QUIT, 0, 0 );
15967     WaitForSingleObject( thread, 10000 );
15968     CloseHandle( thread );
15969 }
15970 
15971 static const struct message WmSetParentSeq_1[] = {
15972     { WM_SHOWWINDOW, sent|wparam, 0 },
15973     { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15974     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
15975     { WM_CHILDACTIVATE, sent },
15976     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE },
15977     { WM_MOVE, sent|defwinproc|wparam, 0 },
15978     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15979     { WM_SHOWWINDOW, sent|wparam, 1 },
15980     { 0 }
15981 };
15982 
15983 static const struct message WmSetParentSeq_2[] = {
15984     { WM_SHOWWINDOW, sent|wparam, 0 },
15985     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
15986     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
15987     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
15988     { HCBT_SETFOCUS, hook|optional },
15989     { WM_NCACTIVATE, sent|wparam|optional, 0 },
15990     { WM_ACTIVATE, sent|wparam|optional, 0 },
15991     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
15992     { WM_KILLFOCUS, sent|wparam, 0 },
15993     { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15994     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
15995     { HCBT_ACTIVATE, hook|optional },
15996     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
15997     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
15998     { WM_NCACTIVATE, sent|wparam|optional, 1 },
15999     { WM_ACTIVATE, sent|wparam|optional, 1 },
16000     { HCBT_SETFOCUS, hook|optional },
16001     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
16002     { WM_SETFOCUS, sent|optional|defwinproc },
16003     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOCLIENTSIZE },
16004     { WM_MOVE, sent|defwinproc|wparam, 0 },
16005     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
16006     { WM_SHOWWINDOW, sent|wparam, 1 },
16007     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
16008     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
16009     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
16010     { 0 }
16011 };
16012 
16013 
16014 static void test_SetParent(void)
16015 {
16016     HWND parent1, parent2, child, popup;
16017     RECT rc, rc_old;
16018 
16019     parent1 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
16020                             100, 100, 200, 200, 0, 0, 0, NULL);
16021     ok(parent1 != 0, "Failed to create parent1 window\n");
16022 
16023     parent2 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
16024                             400, 100, 200, 200, 0, 0, 0, NULL);
16025     ok(parent2 != 0, "Failed to create parent2 window\n");
16026 
16027     /* WS_CHILD window */
16028     child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD | WS_VISIBLE,
16029                            10, 10, 150, 150, parent1, 0, 0, NULL);
16030     ok(child != 0, "Failed to create child window\n");
16031 
16032     GetWindowRect(parent1, &rc);
16033     trace("parent1 %s\n", wine_dbgstr_rect(&rc));
16034     GetWindowRect(child, &rc_old);
16035     MapWindowPoints(0, parent1, (POINT *)&rc_old, 2);
16036     trace("child %s\n", wine_dbgstr_rect(&rc_old));
16037 
16038     flush_sequence();
16039 
16040     SetParent(child, parent2);
16041     flush_events();
16042     ok_sequence(WmSetParentSeq_1, "SetParent() visible WS_CHILD", TRUE);
16043 
16044     ok(GetWindowLongA(child, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
16045     ok(!IsWindowVisible(child), "IsWindowVisible() should return FALSE\n");
16046 
16047     GetWindowRect(parent2, &rc);
16048     trace("parent2 %s\n", wine_dbgstr_rect(&rc));
16049     GetWindowRect(child, &rc);
16050     MapWindowPoints(0, parent2, (POINT *)&rc, 2);
16051     trace("child %s\n", wine_dbgstr_rect(&rc));
16052 
16053     ok(EqualRect(&rc_old, &rc), "rects do not match %s / %s\n", wine_dbgstr_rect(&rc_old),
16054        wine_dbgstr_rect(&rc));
16055 
16056     /* WS_POPUP window */
16057     popup = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP | WS_VISIBLE,
16058                            20, 20, 100, 100, 0, 0, 0, NULL);
16059     ok(popup != 0, "Failed to create popup window\n");
16060 
16061     GetWindowRect(popup, &rc_old);
16062     trace("popup %s\n", wine_dbgstr_rect(&rc_old));
16063 
16064     flush_sequence();
16065 
16066     SetParent(popup, child);
16067     flush_events();
16068     ok_sequence(WmSetParentSeq_2, "SetParent() visible WS_POPUP", TRUE);
16069 
16070     ok(GetWindowLongA(popup, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
16071     ok(!IsWindowVisible(popup), "IsWindowVisible() should return FALSE\n");
16072 
16073     GetWindowRect(child, &rc);
16074     trace("parent2 %s\n", wine_dbgstr_rect(&rc));
16075     GetWindowRect(popup, &rc);
16076     MapWindowPoints(0, child, (POINT *)&rc, 2);
16077     trace("popup %s\n", wine_dbgstr_rect(&rc));
16078 
16079     ok(EqualRect(&rc_old, &rc), "rects do not match %s / %s\n", wine_dbgstr_rect(&rc_old),
16080        wine_dbgstr_rect(&rc));
16081 
16082     DestroyWindow(popup);
16083     DestroyWindow(child);
16084     DestroyWindow(parent1);
16085     DestroyWindow(parent2);
16086 
16087     flush_sequence();
16088 }
16089 
16090 static const struct message WmKeyReleaseOnly[] = {
16091     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x80000001 },
16092     { WM_KEYUP, sent|wparam|lparam, 0x41, 0x80000001 },
16093     { 0 }
16094 };
16095 static const struct message WmKeyPressNormal[] = {
16096     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x1 },
16097     { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x1 },
16098     { 0 }
16099 };
16100 static const struct message WmKeyPressRepeat[] = {
16101     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x40000001 },
16102     { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x40000001 },
16103     { 0 }
16104 };
16105 static const struct message WmKeyReleaseNormal[] = {
16106     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0xc0000001 },
16107     { WM_KEYUP, sent|wparam|lparam, 0x41, 0xc0000001 },
16108     { 0 }
16109 };
16110 
16111 static void test_keyflags(void)
16112 {
16113     HWND test_window;
16114     SHORT key_state;
16115     BYTE keyboard_state[256];
16116     MSG msg;
16117 
16118     test_window = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
16119                            100, 100, 200, 200, 0, 0, 0, NULL);
16120 
16121     flush_events();
16122     flush_sequence();
16123 
16124     /* keyup without a keydown */
16125     keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
16126     while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16127         DispatchMessageA(&msg);
16128     ok_sequence(WmKeyReleaseOnly, "key release only", TRUE);
16129 
16130     key_state = GetAsyncKeyState(0x41);
16131     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16132 
16133     key_state = GetKeyState(0x41);
16134     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16135 
16136     /* keydown */
16137     keybd_event(0x41, 0, 0, 0);
16138     while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16139         DispatchMessageA(&msg);
16140     ok_sequence(WmKeyPressNormal, "key press only", FALSE);
16141 
16142     key_state = GetAsyncKeyState(0x41);
16143     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16144 
16145     key_state = GetKeyState(0x41);
16146     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16147 
16148     /* keydown repeat */
16149     keybd_event(0x41, 0, 0, 0);
16150     while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16151         DispatchMessageA(&msg);
16152     ok_sequence(WmKeyPressRepeat, "key press repeat", FALSE);
16153 
16154     key_state = GetAsyncKeyState(0x41);
16155     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16156 
16157     key_state = GetKeyState(0x41);
16158     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16159 
16160     /* keyup */
16161     keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
16162     while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16163         DispatchMessageA(&msg);
16164     ok_sequence(WmKeyReleaseNormal, "key release repeat", FALSE);
16165 
16166     key_state = GetAsyncKeyState(0x41);
16167     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16168 
16169     key_state = GetKeyState(0x41);
16170     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16171 
16172     /* set the key state in this thread */
16173     GetKeyboardState(keyboard_state);
16174     keyboard_state[0x41] = 0x80;
16175     SetKeyboardState(keyboard_state);
16176 
16177     key_state = GetAsyncKeyState(0x41);
16178     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16179 
16180     /* keydown */
16181     keybd_event(0x41, 0, 0, 0);
16182     while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16183         DispatchMessageA(&msg);
16184     ok_sequence(WmKeyPressRepeat, "key press after setkeyboardstate", TRUE);
16185 
16186     key_state = GetAsyncKeyState(0x41);
16187     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16188 
16189     key_state = GetKeyState(0x41);
16190     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16191 
16192     /* clear the key state in this thread */
16193     GetKeyboardState(keyboard_state);
16194     keyboard_state[0x41] = 0;
16195     SetKeyboardState(keyboard_state);
16196 
16197     key_state = GetAsyncKeyState(0x41);
16198     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16199 
16200     /* keyup */
16201     keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
16202     while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16203         DispatchMessageA(&msg);
16204     ok_sequence(WmKeyReleaseOnly, "key release after setkeyboardstate", TRUE);
16205 
16206     key_state = GetAsyncKeyState(0x41);
16207     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16208 
16209     key_state = GetKeyState(0x41);
16210     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16211 
16212     DestroyWindow(test_window);
16213     flush_sequence();
16214 }
16215 
16216 static const struct message WmHotkeyPressLWIN[] = {
16217     { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
16218     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
16219     { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
16220     { 0 }
16221 };
16222 static const struct message WmHotkeyPress[] = {
16223     { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16224     { WM_HOTKEY, sent|wparam, 5 },
16225     { 0 }
16226 };
16227 static const struct message WmHotkeyRelease[] = {
16228     { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16229     { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 0x80000001 },
16230     { WM_KEYUP, sent|lparam, 0, 0x80000001 },
16231     { 0 }
16232 };
16233 static const struct message WmHotkeyReleaseLWIN[] = {
16234     { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
16235     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
16236     { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
16237     { 0 }
16238 };
16239 static const struct message WmHotkeyCombined[] = {
16240     { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
16241     { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16242     { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16243     { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
16244     { WM_APP, sent, 0, 0 },
16245     { WM_HOTKEY, sent|wparam, 5 },
16246     { WM_APP+1, sent, 0, 0 },
16247     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
16248     { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
16249     { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
16250     { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
16251     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
16252     { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
16253     { 0 }
16254 };
16255 static const struct message WmHotkeyPrevious[] = {
16256     { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
16257     { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16258     { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16259     { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
16260     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
16261     { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
16262     { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 1 },
16263     { WM_KEYDOWN, sent|lparam, 0, 1 },
16264     { HCBT_KEYSKIPPED, hook|optional|lparam, 0, 0xc0000001 },
16265     { WM_KEYUP, sent|lparam, 0, 0xc0000001 },
16266     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
16267     { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
16268     { 0 }
16269 };
16270 static const struct message WmHotkeyNew[] = {
16271     { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16272     { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16273     { WM_HOTKEY, sent|wparam, 5 },
16274     { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
16275     { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
16276     { 0 }
16277 };
16278 
16279 static int hotkey_letter;
16280 
16281 static LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
16282 {
16283     struct recvd_message msg;
16284 
16285     if (nCode == HC_ACTION)
16286     {
16287         KBDLLHOOKSTRUCT *kdbhookstruct = (KBDLLHOOKSTRUCT*)lParam;
16288 
16289         msg.hwnd = 0;
16290         msg.message = wParam;
16291         msg.flags = kbd_hook|wparam|lparam;
16292         msg.wParam = kdbhookstruct->vkCode;
16293         msg.lParam = kdbhookstruct->flags;
16294         msg.descr = "KeyboardHookProc";
16295         add_message(&msg);
16296 
16297         if (wParam == WM_KEYUP || wParam == WM_KEYDOWN)
16298         {
16299             ok(kdbhookstruct->vkCode == VK_LWIN || kdbhookstruct->vkCode == hotkey_letter,
16300                "unexpected keycode %x\n", kdbhookstruct->vkCode);
16301        }
16302     }
16303 
16304     return CallNextHookEx(hKBD_hook, nCode, wParam, lParam);
16305 }
16306 
16307 static void test_hotkey(void)
16308 {
16309     HWND test_window, taskbar_window;
16310     BOOL ret;
16311     MSG msg;
16312     DWORD queue_status;
16313     SHORT key_state;
16314 
16315     SetLastError(0xdeadbeef);
16316     ret = UnregisterHotKey(NULL, 0);
16317     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16318     ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16319        "unexpected error %d\n", GetLastError());
16320 
16321     if (ret == TRUE)
16322     {
16323         skip("hotkeys not supported\n");
16324         return;
16325     }
16326 
16327     test_window = CreateWindowExA(0, "HotkeyWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
16328                            100, 100, 200, 200, 0, 0, 0, NULL);
16329 
16330     flush_sequence();
16331 
16332     SetLastError(0xdeadbeef);
16333     ret = UnregisterHotKey(test_window, 0);
16334     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16335     ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16336        "unexpected error %d\n", GetLastError());
16337 
16338     /* Search for a Windows Key + letter combination that hasn't been registered */
16339     for (hotkey_letter = 0x41; hotkey_letter <= 0x51; hotkey_letter ++)
16340     {
16341         SetLastError(0xdeadbeef);
16342         ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
16343 
16344         if (ret == TRUE)
16345         {
16346             break;
16347         }
16348         else
16349         {
16350             ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16351                "unexpected error %d\n", GetLastError());
16352         }
16353     }
16354 
16355     if (hotkey_letter == 0x52)
16356     {
16357         ok(0, "Couldn't find any free Windows Key + letter combination\n");
16358         goto end;
16359     }
16360 
16361     hKBD_hook = SetWindowsHookExA(WH_KEYBOARD_LL, KeyboardHookProc, GetModuleHandleA(NULL), 0);
16362     if (!hKBD_hook) win_skip("WH_KEYBOARD_LL is not supported\n");
16363 
16364     /* Same key combination, different id */
16365     SetLastError(0xdeadbeef);
16366     ret = RegisterHotKey(test_window, 4, MOD_WIN, hotkey_letter);
16367     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16368     ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16369        "unexpected error %d\n", GetLastError());
16370 
16371     /* Same key combination, different window */
16372     SetLastError(0xdeadbeef);
16373     ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
16374     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16375     ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16376        "unexpected error %d\n", GetLastError());
16377 
16378     /* Register the same hotkey twice */
16379     SetLastError(0xdeadbeef);
16380     ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
16381     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16382     ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16383        "unexpected error %d\n", GetLastError());
16384 
16385     /* Window on another thread */
16386     taskbar_window = FindWindowA("Shell_TrayWnd", NULL);
16387     if (!taskbar_window)
16388     {
16389         skip("no taskbar?\n");
16390     }
16391     else
16392     {
16393         SetLastError(0xdeadbeef);
16394         ret = RegisterHotKey(taskbar_window, 5, 0, hotkey_letter);
16395         ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16396         ok(GetLastError() == ERROR_WINDOW_OF_OTHER_THREAD || broken(GetLastError() == 0xdeadbeef),
16397            "unexpected error %d\n", GetLastError());
16398     }
16399 
16400     /* Inject the appropriate key sequence */
16401     keybd_event(VK_LWIN, 0, 0, 0);
16402     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16403         DispatchMessageA(&msg);
16404     ok_sequence(WmHotkeyPressLWIN, "window hotkey press LWIN", FALSE);
16405 
16406     keybd_event(hotkey_letter, 0, 0, 0);
16407     queue_status = GetQueueStatus(QS_HOTKEY);
16408     ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
16409     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16410     {
16411         if (msg.message == WM_HOTKEY)
16412         {
16413             ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
16414             ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
16415         }
16416         DispatchMessageA(&msg);
16417     }
16418     ok_sequence(WmHotkeyPress, "window hotkey press", FALSE);
16419 
16420     queue_status = GetQueueStatus(QS_HOTKEY);
16421     ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
16422 
16423     key_state = GetAsyncKeyState(hotkey_letter);
16424     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16425 
16426     keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16427     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16428         DispatchMessageA(&msg);
16429     ok_sequence(WmHotkeyRelease, "window hotkey release", TRUE);
16430 
16431     keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
16432     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16433         DispatchMessageA(&msg);
16434     ok_sequence(WmHotkeyReleaseLWIN, "window hotkey release LWIN", FALSE);
16435 
16436     /* normal posted WM_HOTKEY messages set QS_HOTKEY */
16437     PostMessageA(test_window, WM_HOTKEY, 0, 0);
16438     queue_status = GetQueueStatus(QS_HOTKEY);
16439     ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
16440     queue_status = GetQueueStatus(QS_POSTMESSAGE);
16441     ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
16442     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16443         DispatchMessageA(&msg);
16444     flush_sequence();
16445 
16446     /* Send and process all messages at once */
16447     PostMessageA(test_window, WM_APP, 0, 0);
16448     keybd_event(VK_LWIN, 0, 0, 0);
16449     keybd_event(hotkey_letter, 0, 0, 0);
16450     keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16451     keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
16452 
16453     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16454     {
16455         if (msg.message == WM_HOTKEY)
16456         {
16457             ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
16458             ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
16459         }
16460         DispatchMessageA(&msg);
16461     }
16462     ok_sequence(WmHotkeyCombined, "window hotkey combined", FALSE);
16463 
16464     /* Register same hwnd/id with different key combination */
16465     ret = RegisterHotKey(test_window, 5, 0, hotkey_letter);
16466     ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
16467 
16468     /* Previous key combination does not work */
16469     keybd_event(VK_LWIN, 0, 0, 0);
16470     keybd_event(hotkey_letter, 0, 0, 0);
16471     keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16472     keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
16473 
16474     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16475         DispatchMessageA(&msg);
16476     ok_sequence(WmHotkeyPrevious, "window hotkey previous", FALSE);
16477 
16478     /* New key combination works */
16479     keybd_event(hotkey_letter, 0, 0, 0);
16480     keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16481 
16482     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16483     {
16484         if (msg.message == WM_HOTKEY)
16485         {
16486             ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
16487             ok(msg.lParam == MAKELPARAM(0, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
16488         }
16489         DispatchMessageA(&msg);
16490     }
16491     ok_sequence(WmHotkeyNew, "window hotkey new", FALSE);
16492 
16493     /* Unregister hotkey properly */
16494     ret = UnregisterHotKey(test_window, 5);
16495     ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
16496 
16497     /* Unregister hotkey again */
16498     SetLastError(0xdeadbeef);
16499     ret = UnregisterHotKey(test_window, 5);
16500     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16501     ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16502        "unexpected error %d\n", GetLastError());
16503 
16504     /* Register thread hotkey */
16505     ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
16506     ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
16507 
16508     /* Inject the appropriate key sequence */
16509     keybd_event(VK_LWIN, 0, 0, 0);
16510     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16511     {
16512         ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
16513         DispatchMessageA(&msg);
16514     }
16515     ok_sequence(WmHotkeyPressLWIN, "thread hotkey press LWIN", FALSE);
16516 
16517     keybd_event(hotkey_letter, 0, 0, 0);
16518     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16519     {
16520         if (msg.message == WM_HOTKEY)
16521         {
16522             struct recvd_message message;
16523             ok(msg.hwnd == NULL, "unexpected hwnd %p\n", msg.hwnd);
16524             ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
16525             message.message = msg.message;
16526             message.flags = sent|wparam|lparam;
16527             message.wParam = msg.wParam;
16528             message.lParam = msg.lParam;
16529             message.descr = "test_hotkey thread message";
16530             add_message(&message);
16531         }
16532         else
16533             ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
16534         DispatchMessageA(&msg);
16535     }
16536     ok_sequence(WmHotkeyPress, "thread hotkey press", FALSE);
16537 
16538     keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16539     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16540     {
16541         ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
16542         DispatchMessageA(&msg);
16543     }
16544     ok_sequence(WmHotkeyRelease, "thread hotkey release", TRUE);
16545 
16546     keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
16547     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16548     {
16549         ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
16550         DispatchMessageA(&msg);
16551     }
16552     ok_sequence(WmHotkeyReleaseLWIN, "thread hotkey release LWIN", FALSE);
16553 
16554     /* Unregister thread hotkey */
16555     ret = UnregisterHotKey(NULL, 5);
16556     ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
16557 
16558     if (hKBD_hook) UnhookWindowsHookEx(hKBD_hook);
16559     hKBD_hook = NULL;
16560 
16561 end:
16562     UnregisterHotKey(NULL, 5);
16563     UnregisterHotKey(test_window, 5);
16564     DestroyWindow(test_window);
16565     flush_sequence();
16566 }
16567 
16568 
16569 static const struct message WmSetFocus_1[] = {
16570     { HCBT_SETFOCUS, hook }, /* child */
16571     { HCBT_ACTIVATE, hook }, /* parent */
16572     { WM_QUERYNEWPALETTE, sent|wparam|lparam|parent|optional, 0, 0 },
16573     { WM_WINDOWPOSCHANGING, sent|parent, 0, SWP_NOSIZE|SWP_NOMOVE },
16574     { WM_ACTIVATEAPP, sent|wparam|parent, 1 },
16575     { WM_NCACTIVATE, sent|parent },
16576     { WM_GETTEXT, sent|defwinproc|parent|optional },
16577     { WM_GETTEXT, sent|defwinproc|parent|optional },
16578     { WM_ACTIVATE, sent|wparam|parent, 1 },
16579     { HCBT_SETFOCUS, hook }, /* parent */
16580     { WM_SETFOCUS, sent|defwinproc|parent },
16581     { WM_KILLFOCUS, sent|parent },
16582     { WM_SETFOCUS, sent },
16583     { 0 }
16584 };
16585 static const struct message WmSetFocus_2[] = {
16586     { HCBT_SETFOCUS, hook }, /* parent */
16587     { WM_KILLFOCUS, sent },
16588     { WM_SETFOCUS, sent|parent },
16589     { 0 }
16590 };
16591 static const struct message WmSetFocus_3[] = {
16592     { HCBT_SETFOCUS, hook }, /* child */
16593     { 0 }
16594 };
16595 
16596 static void test_SetFocus(void)
16597 {
16598     HWND parent, old_parent, child, old_focus, old_active;
16599     MSG msg;
16600     struct wnd_event wnd_event;
16601     HANDLE hthread;
16602     DWORD ret, tid;
16603 
16604     wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
16605     ok(wnd_event.start_event != 0, "CreateEvent error %d\n", GetLastError());
16606     hthread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
16607     ok(hthread != 0, "CreateThread error %d\n", GetLastError());
16608     ret = WaitForSingleObject(wnd_event.start_event, INFINITE);
16609     ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
16610     CloseHandle(wnd_event.start_event);
16611 
16612     parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
16613                             0, 0, 0, 0, 0, 0, 0, NULL);
16614     ok(parent != 0, "failed to create parent window\n");
16615     child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
16616                            0, 0, 0, 0, parent, 0, 0, NULL);
16617     ok(child != 0, "failed to create child window\n");
16618 
16619     trace("parent %p, child %p, thread window %p\n", parent, child, wnd_event.hwnd);
16620 
16621     SetFocus(0);
16622     SetActiveWindow(0);
16623 
16624     flush_events();
16625     flush_sequence();
16626 
16627     ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
16628     ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
16629 
16630     log_all_parent_messages++;
16631 
16632     old_focus = SetFocus(child);
16633     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16634     ok_sequence(WmSetFocus_1, "SetFocus on a child window", TRUE);
16635     ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
16636     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16637     ok(GetFocus() == child, "expected focus %p, got %p\n", child, GetFocus());
16638 
16639     old_focus = SetFocus(parent);
16640     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16641     ok_sequence(WmSetFocus_2, "SetFocus on a parent window", FALSE);
16642     ok(old_focus == child, "expected old focus %p, got %p\n", child, old_focus);
16643     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16644     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16645 
16646     SetLastError(0xdeadbeef);
16647     old_focus = SetFocus((HWND)0xdeadbeef);
16648     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
16649        "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
16650     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16651     ok_sequence(WmEmptySeq, "SetFocus on an invalid window", FALSE);
16652     ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
16653     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16654     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16655 
16656     SetLastError(0xdeadbeef);
16657     old_focus = SetFocus(GetDesktopWindow());
16658     ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
16659        broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
16660     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16661     ok_sequence(WmEmptySeq, "SetFocus on a desktop window", TRUE);
16662     ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
16663     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16664     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16665 
16666     SetLastError(0xdeadbeef);
16667     old_focus = SetFocus(wnd_event.hwnd);
16668     ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
16669        broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
16670     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16671     ok_sequence(WmEmptySeq, "SetFocus on another thread window", TRUE);
16672     ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
16673     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16674     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16675 
16676     SetLastError(0xdeadbeef);
16677     old_active = SetActiveWindow((HWND)0xdeadbeef);
16678     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
16679        "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
16680     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16681     ok_sequence(WmEmptySeq, "SetActiveWindow on an invalid window", FALSE);
16682     ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
16683     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16684     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16685 
16686     SetLastError(0xdeadbeef);
16687     old_active = SetActiveWindow(GetDesktopWindow());
16688 todo_wine
16689     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
16690     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16691     ok_sequence(WmEmptySeq, "SetActiveWindow on a desktop window", TRUE);
16692     ok(old_active == 0, "expected old focus 0, got %p\n", old_focus);
16693     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16694     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16695 
16696     SetLastError(0xdeadbeef);
16697     old_active = SetActiveWindow(wnd_event.hwnd);
16698 todo_wine
16699     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
16700     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16701     ok_sequence(WmEmptySeq, "SetActiveWindow on another thread window", TRUE);
16702     ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
16703     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16704     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16705 
16706     SetLastError(0xdeadbeef);
16707     ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE);
16708     ok(ret, "AttachThreadInput error %d\n", GetLastError());
16709 
16710     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16711     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16712 
16713     flush_events();
16714     flush_sequence();
16715 
16716     old_focus = SetFocus(wnd_event.hwnd);
16717     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16718     ok(old_focus == wnd_event.hwnd, "expected old focus %p, got %p\n", wnd_event.hwnd, old_focus);
16719     ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
16720     ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
16721 
16722     old_focus = SetFocus(parent);
16723     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16724     ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
16725     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16726     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16727 
16728     flush_events();
16729     flush_sequence();
16730 
16731     old_active = SetActiveWindow(wnd_event.hwnd);
16732     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16733     ok(old_active == parent, "expected old focus %p, got %p\n", parent, old_active);
16734     ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
16735     ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
16736 
16737     SetLastError(0xdeadbeef);
16738     ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE);
16739     ok(ret, "AttachThreadInput error %d\n", GetLastError());
16740 
16741     ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
16742     ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
16743 
16744     old_parent = SetParent(child, GetDesktopWindow());
16745     ok(old_parent == parent, "expected old parent %p, got %p\n", parent, old_parent);
16746 
16747     ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
16748     ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
16749 
16750     old_focus = SetFocus(parent);
16751     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16752     ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
16753     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16754     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16755 
16756     flush_events();
16757     flush_sequence();
16758 
16759     SetLastError(0xdeadbeef);
16760     old_focus = SetFocus(child);
16761 todo_wine
16762     ok(GetLastError() == ERROR_INVALID_PARAMETER /* Vista+ */ ||
16763        broken(GetLastError() == 0) /* XP */ ||
16764        broken(GetLastError() == 0xdeadbeef), "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
16765     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16766     ok_sequence(WmSetFocus_3, "SetFocus on a child window", TRUE);
16767     ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
16768     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16769     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16770 
16771     SetLastError(0xdeadbeef);
16772     old_active = SetActiveWindow(child);
16773     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
16774     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16775     ok_sequence(WmEmptySeq, "SetActiveWindow on a child window", FALSE);
16776     ok(old_active == parent, "expected old active %p, got %p\n", parent, old_active);
16777     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16778     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16779 
16780     log_all_parent_messages--;
16781 
16782     DestroyWindow(child);
16783     DestroyWindow(parent);
16784 
16785     ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
16786     ok(ret, "PostMessage(WM_QUIT) error %d\n", GetLastError());
16787     ret = WaitForSingleObject(hthread, INFINITE);
16788     ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
16789     CloseHandle(hthread);
16790 }
16791 
16792 static const struct message WmSetLayeredStyle[] = {
16793     { WM_STYLECHANGING, sent },
16794     { WM_STYLECHANGED, sent },
16795     { WM_GETTEXT, sent|defwinproc|optional },
16796     { 0 }
16797 };
16798 
16799 static const struct message WmSetLayeredStyle2[] = {
16800     { WM_STYLECHANGING, sent },
16801     { WM_STYLECHANGED, sent },
16802     { WM_WINDOWPOSCHANGING, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
16803     { WM_NCCALCSIZE, sent|optional|wparam|defwinproc, 1 },
16804     { WM_WINDOWPOSCHANGED, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
16805     { WM_MOVE, sent|optional|defwinproc|wparam, 0 },
16806     { WM_SIZE, sent|optional|defwinproc|wparam, SIZE_RESTORED },
16807     { 0 }
16808 };
16809 
16810 struct layered_window_info
16811 {
16812     HWND   hwnd;
16813     HDC    hdc;
16814     SIZE   size;
16815     HANDLE event;
16816     BOOL   ret;
16817 };
16818 
16819 static DWORD CALLBACK update_layered_proc( void *param )
16820 {
16821     struct layered_window_info *info = param;
16822     POINT src = { 0, 0 };
16823 
16824     info->ret = pUpdateLayeredWindow( info->hwnd, 0, NULL, &info->size,
16825                                       info->hdc, &src, 0, NULL, ULW_OPAQUE );
16826     ok( info->ret, "failed\n");
16827     SetEvent( info->event );
16828     return 0;
16829 }
16830 
16831 static void test_layered_window(void)
16832 {
16833     HWND hwnd;
16834     HDC hdc;
16835     HBITMAP bmp;
16836     BOOL ret;
16837     SIZE size;
16838     POINT pos, src;
16839     RECT rect, client;
16840     HANDLE thread;
16841     DWORD tid;
16842     struct layered_window_info info;
16843 
16844     if (!pUpdateLayeredWindow)
16845     {
16846         win_skip( "UpdateLayeredWindow not supported\n" );
16847         return;
16848     }
16849 
16850     hdc = CreateCompatibleDC( 0 );
16851     bmp = CreateCompatibleBitmap( hdc, 300, 300 );
16852     SelectObject( hdc, bmp );
16853 
16854     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_CAPTION | WS_THICKFRAME | WS_SYSMENU,
16855                            100, 100, 300, 300, 0, 0, 0, NULL);
16856     ok( hwnd != 0, "failed to create window\n" );
16857     ShowWindow( hwnd, SW_SHOWNORMAL );
16858     UpdateWindow( hwnd );
16859     flush_events();
16860     flush_sequence();
16861 
16862     GetWindowRect( hwnd, &rect );
16863     GetClientRect( hwnd, &client );
16864     ok( client.right < rect.right - rect.left, "wrong client area\n" );
16865     ok( client.bottom < rect.bottom - rect.top, "wrong client area\n" );
16866 
16867     src.x = src.y = 0;
16868     pos.x = pos.y = 300;
16869     size.cx = size.cy = 250;
16870     ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16871     ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
16872     ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
16873     SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
16874     ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
16875 
16876     ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16877     ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
16878     ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
16879     GetWindowRect( hwnd, &rect );
16880     ok( rect.left == 300 && rect.top == 300 && rect.right == 550 && rect.bottom == 550,
16881         "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
16882     GetClientRect( hwnd, &rect );
16883     ok( rect.right == client.right - 50 && rect.bottom == client.bottom - 50,
16884         "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
16885 
16886     size.cx = 150;
16887     pos.y = 200;
16888     ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16889     ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
16890     ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
16891     GetWindowRect( hwnd, &rect );
16892     ok( rect.left == 300 && rect.top == 200 && rect.right == 450 && rect.bottom == 450,
16893         "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
16894     GetClientRect( hwnd, &rect );
16895     ok( rect.right == client.right - 150 && rect.bottom == client.bottom - 50,
16896         "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
16897 
16898     SetWindowLongA( hwnd, GWL_STYLE,
16899                    GetWindowLongA(hwnd, GWL_STYLE) & ~(WS_CAPTION | WS_THICKFRAME | WS_SYSMENU) );
16900     ok_sequence( WmSetLayeredStyle2, "WmSetLayeredStyle2", FALSE );
16901 
16902     size.cx = 200;
16903     pos.x = 200;
16904     ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16905     ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
16906     ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
16907     GetWindowRect( hwnd, &rect );
16908     ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
16909         "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
16910     GetClientRect( hwnd, &rect );
16911     ok( (rect.right == 200 && rect.bottom == 250) ||
16912         broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
16913         "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
16914 
16915     size.cx = 0;
16916     ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16917     ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
16918     ok( GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == ERROR_MR_MID_NOT_FOUND) ||
16919         broken(GetLastError() == ERROR_GEN_FAILURE) /* win7 */, "wrong error %u\n", GetLastError() );
16920     size.cx = 1;
16921     size.cy = -1;
16922     ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16923     ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
16924     ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
16925 
16926     SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED );
16927     ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
16928     GetWindowRect( hwnd, &rect );
16929     ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
16930         "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
16931     GetClientRect( hwnd, &rect );
16932     ok( (rect.right == 200 && rect.bottom == 250) ||
16933         broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
16934         "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
16935 
16936     SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
16937     info.hwnd = hwnd;
16938     info.hdc = hdc;
16939     info.size.cx = 250;
16940     info.size.cy = 300;
16941     info.event = CreateEventA( NULL, TRUE, FALSE, NULL );
16942     info.ret = FALSE;
16943     thread = CreateThread( NULL, 0, update_layered_proc, &info, 0, &tid );
16944     ok( WaitForSingleObject( info.event, 1000 ) == 0, "wait failed\n" );
16945     ok( info.ret, "UpdateLayeredWindow failed in other thread\n" );
16946     WaitForSingleObject( thread, 1000 );
16947     CloseHandle( thread );
16948     GetWindowRect( hwnd, &rect );
16949     ok( rect.left == 200 && rect.top == 200 && rect.right == 450 && rect.bottom == 500,
16950         "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
16951     GetClientRect( hwnd, &rect );
16952     ok( (rect.right == 250 && rect.bottom == 300) ||
16953         broken(rect.right == client.right - 50 && rect.bottom == client.bottom),
16954         "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
16955 
16956     DestroyWindow( hwnd );
16957     DeleteDC( hdc );
16958     DeleteObject( bmp );
16959 }
16960 
16961 static HMENU hpopupmenu;
16962 
16963 static LRESULT WINAPI cancel_popup_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
16964 {
16965     if (ignore_message( message )) return 0;
16966 
16967     switch (message) {
16968     case WM_ENTERIDLE:
16969         todo_wine ok(GetCapture() == hwnd, "expected %p, got %p\n", hwnd, GetCapture());
16970         EndMenu();
16971         break;
16972     case WM_INITMENU:
16973     case WM_INITMENUPOPUP:
16974     case WM_UNINITMENUPOPUP:
16975         ok((HMENU)wParam == hpopupmenu, "expected %p, got %lx\n", hpopupmenu, wParam);
16976         break;
16977     case WM_CAPTURECHANGED:
16978         todo_wine ok(!lParam || (HWND)lParam == hwnd, "lost capture to %lx\n", lParam);
16979         break;
16980     }
16981 
16982     return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
16983 }
16984 
16985 static LRESULT WINAPI cancel_init_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
16986 {
16987     if (ignore_message( message )) return 0;
16988 
16989     switch (message) {
16990     case WM_ENTERMENULOOP:
16991         ok(EndMenu() == TRUE, "EndMenu() failed\n");
16992         break;
16993     }
16994 
16995     return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
16996 }
16997 
16998 static void test_TrackPopupMenu(void)
16999 {
17000     MSG msg;
17001     HWND hwnd;
17002     BOOL ret;
17003 
17004     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
17005                            0, 0, 1, 1, 0,
17006                            NULL, NULL, 0);
17007     ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
17008 
17009     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
17010 
17011     hpopupmenu = CreatePopupMenu();
17012     ok(hpopupmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
17013 
17014     AppendMenuA(hpopupmenu, MF_STRING, 100, "item 1");
17015     AppendMenuA(hpopupmenu, MF_STRING, 100, "item 2");
17016 
17017     flush_events();
17018     flush_sequence();
17019     ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
17020     ok_sequence(WmTrackPopupMenu, "TrackPopupMenu", TRUE);
17021     ok(ret == 1, "TrackPopupMenu failed with error %i\n", GetLastError());
17022 
17023     /* Test popup closing with an ESC-press */
17024     flush_events();
17025     PostMessageW(hwnd, WM_KEYDOWN, VK_ESCAPE, 0);
17026     ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
17027     ok(ret == 1, "TrackPopupMenu failed with error %i\n", GetLastError());
17028     PostQuitMessage(0);
17029     flush_sequence();
17030     while ( PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) )
17031     {
17032         TranslateMessage(&msg);
17033         DispatchMessageA(&msg);
17034     }
17035     ok_sequence(WmTrackPopupMenuEsc, "TrackPopupMenuEsc", FALSE); /* Shouldn't get any message */
17036 
17037     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_init_proc);
17038 
17039     flush_events();
17040     flush_sequence();
17041     ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
17042     ok_sequence(WmTrackPopupMenuAbort, "WmTrackPopupMenuAbort", TRUE);
17043     ok(ret == TRUE, "TrackPopupMenu failed\n");
17044 
17045     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
17046 
17047     SetCapture(hwnd);
17048 
17049     flush_events();
17050     flush_sequence();
17051     ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
17052     ok_sequence(WmTrackPopupMenuCapture, "TrackPopupMenuCapture", TRUE);
17053     ok(ret == 1, "TrackPopupMenuCapture failed with error %i\n", GetLastError());
17054 
17055     DestroyMenu(hpopupmenu);
17056     DestroyWindow(hwnd);
17057 }
17058 
17059 static void test_TrackPopupMenuEmpty(void)
17060 {
17061     HWND hwnd;
17062     BOOL ret;
17063 
17064     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
17065                            0, 0, 1, 1, 0,
17066                            NULL, NULL, 0);
17067     ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
17068 
17069     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
17070 
17071     hpopupmenu = CreatePopupMenu();
17072     ok(hpopupmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
17073 
17074     flush_events();
17075     flush_sequence();
17076     ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
17077     ok_sequence(WmTrackPopupMenuEmpty, "TrackPopupMenuEmpty", TRUE);
17078     ok(ret == 0, "TrackPopupMenu succeeded\n");
17079 
17080     DestroyMenu(hpopupmenu);
17081     DestroyWindow(hwnd);
17082 }
17083 
17084 static const struct message send_message_1[] = {
17085     { WM_USER+2, sent|wparam|lparam, 0, 0 },
17086     { WM_USER, sent|wparam|lparam, 0, 0 },
17087     { 0 }
17088 };
17089 static const struct message send_message_2[] = {
17090     { WM_USER+4, sent|wparam|lparam, 0, 0 },
17091     { 0 }
17092 };
17093 static const struct message send_message_3[] = {
17094     { WM_USER+3, sent|wparam|lparam, 0, 0 },
17095     { WM_USER+1, sent|wparam|lparam, 0, 0 },
17096     { 0 }
17097 };
17098 
17099 static DWORD WINAPI SendMessage_thread_1(void *param)
17100 {
17101     struct wnd_event *wnd_event = param;
17102 
17103     trace("thread: starting\n");
17104     WaitForSingleObject(wnd_event->start_event, INFINITE);
17105 
17106     trace("thread: call PostMessage\n");
17107     PostMessageA(wnd_event->hwnd, WM_USER, 0, 0);
17108 
17109     trace("thread: call PostMessage\n");
17110     PostMessageA(wnd_event->hwnd, WM_USER+1, 0, 0);
17111 
17112     trace("thread: call SendMessage\n");
17113     SendMessageA(wnd_event->hwnd, WM_USER+2, 0, 0);
17114 
17115     trace("thread: call SendMessage\n");
17116     SendMessageA(wnd_event->hwnd, WM_USER+3, 0, 0);
17117 
17118     return 0;
17119 }
17120 
17121 static DWORD WINAPI SendMessage_thread_2(void *param)
17122 {
17123     struct wnd_event *wnd_event = param;
17124 
17125     trace("thread: starting\n");
17126     WaitForSingleObject(wnd_event->start_event, INFINITE);
17127 
17128     trace("thread: call PostMessage\n");
17129     PostMessageA(wnd_event->hwnd, WM_USER, 0, 0);
17130 
17131     trace("thread: call PostMessage\n");
17132     PostMessageA(wnd_event->hwnd, WM_USER+1, 0, 0);
17133 
17134     /* this leads to sending an internal message under Wine */
17135     trace("thread: call SetParent\n");
17136     SetParent(wnd_event->hwnd, wnd_event->hwnd);
17137 
17138     trace("thread: call SendMessage\n");
17139     SendMessageA(wnd_event->hwnd, WM_USER+2, 0, 0);
17140 
17141     trace("thread: call SendMessage\n");
17142     SendMessageA(wnd_event->hwnd, WM_USER+3, 0, 0);
17143 
17144     return 0;
17145 }
17146 
17147 static void test_SendMessage_other_thread(int thread_n)
17148 {
17149     DWORD qs_all_input = QS_ALLINPUT & ~QS_RAWINPUT;
17150     HANDLE hthread;
17151     struct wnd_event wnd_event;
17152     DWORD tid, ret;
17153     MSG msg;
17154 
17155     wnd_event.start_event = CreateEventA(NULL, 0, 0, NULL);
17156 
17157     wnd_event.hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
17158                                      100, 100, 200, 200, 0, 0, 0, NULL);
17159     ok(wnd_event.hwnd != 0, "CreateWindowEx failed\n");
17160 
17161     hthread = CreateThread(NULL, 0, thread_n == 1 ? SendMessage_thread_1 : SendMessage_thread_2, &wnd_event, 0, &tid);
17162     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
17163     CloseHandle(hthread);
17164 
17165     flush_events();
17166     flush_sequence();
17167 
17168     ret = GetQueueStatus(QS_SENDMESSAGE);
17169     ok(ret == 0, "wrong status %08x\n", ret);
17170 
17171     SetEvent(wnd_event.start_event);
17172 
17173     /* wait for other thread's SendMessage */
17174     for (;;)
17175     {
17176         ret = GetQueueStatus(QS_SENDMESSAGE);
17177         if (ret == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE)) break;
17178         Sleep(50);
17179     }
17180 
17181     ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17182     ok(ret == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE), "wrong status %08x\n", ret);
17183 
17184     trace("main: call GetMessage\n");
17185     GetMessageA(&msg, 0, 0, 0);
17186     ok(msg.message == WM_USER, "expected WM_USER, got %04x\n", msg.message);
17187     DispatchMessageA(&msg);
17188     ok_sequence(send_message_1, "SendMessage from other thread 1", thread_n == 2);
17189 
17190     /* intentionally yield */
17191     MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input);
17192 
17193     trace("main: call SendMessage\n");
17194     SendMessageA(wnd_event.hwnd, WM_USER+4, 0, 0);
17195     ok_sequence(send_message_2, "SendMessage from other thread 2", FALSE);
17196 
17197     ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17198     ok(ret == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE), "wrong status %08x\n", ret);
17199 
17200     trace("main: call PeekMessage\n");
17201     ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should not fail\n");
17202     ok(msg.message == WM_USER+1, "expected WM_USER+1, got %04x\n", msg.message);
17203     DispatchMessageA(&msg);
17204     ok_sequence(send_message_3, "SendMessage from other thread 3", thread_n == 2);
17205 
17206     /* intentionally yield */
17207     MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input);
17208 
17209     ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17210     /* FIXME: remove once Wine is fixed */
17211 todo_wine_if (thread_n == 2)
17212     ok(ret == 0, "wrong status %08x\n", ret);
17213 
17214     trace("main: call PeekMessage\n");
17215     ok(!PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should fail\n");
17216     ok_sequence(WmEmptySeq, "SendMessage from other thread 5", thread_n == 2);
17217 
17218     ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17219     ok(ret == 0, "wrong status %08x\n", ret);
17220 
17221     trace("main: call DestroyWindow\n");
17222     DestroyWindow(msg.hwnd);
17223 
17224     flush_events();
17225     flush_sequence();
17226 }
17227 
17228 static LRESULT CALLBACK insendmessage_wnd_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
17229 {
17230     DWORD flags = InSendMessageEx( NULL );
17231     BOOL ret;
17232 
17233     switch (msg)
17234     {
17235     case WM_USER:
17236         ok( flags == ISMEX_SEND, "wrong flags %x\n", flags );
17237         ok( InSendMessage(), "InSendMessage returned false\n" );
17238         ret = ReplyMessage( msg );
17239         ok( ret, "ReplyMessage failed err %u\n", GetLastError() );
17240         flags = InSendMessageEx( NULL );
17241         ok( flags == (ISMEX_SEND | ISMEX_REPLIED), "wrong flags %x\n", flags );
17242         ok( InSendMessage(), "InSendMessage returned false\n" );
17243         break;
17244     case WM_USER + 1:
17245         ok( flags == ISMEX_NOTIFY, "wrong flags %x\n", flags );
17246         ok( InSendMessage(), "InSendMessage returned false\n" );
17247         ret = ReplyMessage( msg );
17248         ok( ret, "ReplyMessage failed err %u\n", GetLastError() );
17249         flags = InSendMessageEx( NULL );
17250         ok( flags == ISMEX_NOTIFY, "wrong flags %x\n", flags );
17251         ok( InSendMessage(), "InSendMessage returned false\n" );
17252         break;
17253     case WM_USER + 2:
17254         ok( flags == ISMEX_CALLBACK, "wrong flags %x\n", flags );
17255         ok( InSendMessage(), "InSendMessage returned false\n" );
17256         ret = ReplyMessage( msg );
17257         ok( ret, "ReplyMessage failed err %u\n", GetLastError() );
17258         flags = InSendMessageEx( NULL );
17259         ok( flags == (ISMEX_CALLBACK | ISMEX_REPLIED) || flags == ISMEX_SEND, "wrong flags %x\n", flags );
17260         ok( InSendMessage(), "InSendMessage returned false\n" );
17261         break;
17262     case WM_USER + 3:
17263         ok( flags == ISMEX_NOSEND, "wrong flags %x\n", flags );
17264         ok( !InSendMessage(), "InSendMessage returned true\n" );
17265         ret = ReplyMessage( msg );
17266         ok( !ret, "ReplyMessage succeeded\n" );
17267         break;
17268     }
17269 
17270     return DefWindowProcA( hwnd, msg, wp, lp );
17271 }
17272 
17273 static void CALLBACK msg_callback( HWND hwnd, UINT msg, ULONG_PTR arg, LRESULT result )
17274 {
17275     ok( msg == WM_USER + 2, "wrong msg %x\n", msg );
17276     ok( result == WM_USER + 2, "wrong result %lx\n", result );
17277 }
17278 
17279 static DWORD WINAPI send_message_thread( void *arg )
17280 {
17281     HWND win = arg;
17282 
17283     SendMessageA( win, WM_USER, 0, 0 );
17284     SendNotifyMessageA( win, WM_USER + 1, 0, 0 );
17285     SendMessageCallbackA( win, WM_USER + 2, 0, 0, msg_callback, 0 );
17286     PostMessageA( win, WM_USER + 3, 0, 0 );
17287     PostMessageA( win, WM_QUIT, 0, 0 );
17288     return 0;
17289 }
17290 
17291 static void test_InSendMessage(void)
17292 {
17293     WNDCLASSA cls;
17294     HWND win;
17295     MSG msg;
17296     HANDLE thread;
17297     DWORD tid;
17298 
17299     memset(&cls, 0, sizeof(cls));
17300     cls.lpfnWndProc = insendmessage_wnd_proc;
17301     cls.hInstance = GetModuleHandleA(NULL);
17302     cls.lpszClassName = "InSendMessage_test";
17303     RegisterClassA(&cls);
17304 
17305     win = CreateWindowA( "InSendMessage_test", NULL, 0, 0, 0, 0, 0, NULL, 0, NULL, 0 );
17306     ok( win != NULL, "CreateWindow failed: %d\n", GetLastError() );
17307 
17308     thread = CreateThread( NULL, 0, send_message_thread, win, 0, &tid );
17309     ok( thread != NULL, "CreateThread failed: %d\n", GetLastError() );
17310 
17311     while (GetMessageA(&msg, NULL, 0, 0)) DispatchMessageA( &msg );
17312 
17313     ok( WaitForSingleObject( thread, 30000 ) == WAIT_OBJECT_0, "WaitForSingleObject failed\n" );
17314     CloseHandle( thread );
17315 
17316     DestroyWindow( win );
17317     UnregisterClassA( "InSendMessage_test", GetModuleHandleA(NULL) );
17318 }
17319 
17320 static const struct message DoubleSetCaptureSeq[] =
17321 {
17322     { WM_CAPTURECHANGED, sent },
17323     { 0 }
17324 };
17325 
17326 static void test_DoubleSetCapture(void)
17327 {
17328     HWND hwnd;
17329 
17330     hwnd = CreateWindowExA(0, "TestWindowClass", "Test DoubleSetCapture",
17331                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
17332                            100, 100, 200, 200, 0, 0, 0, NULL);
17333     ok (hwnd != 0, "Failed to create overlapped window\n");
17334 
17335     ShowWindow( hwnd, SW_SHOW );
17336     UpdateWindow( hwnd );
17337     flush_events();
17338     flush_sequence();
17339 
17340     SetCapture( hwnd );
17341     SetCapture( hwnd );
17342     ok_sequence(DoubleSetCaptureSeq, "SetCapture( hwnd ) twice", FALSE);
17343 
17344     DestroyWindow(hwnd);
17345 }
17346 
17347 static void init_funcs(void)
17348 {
17349     HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
17350 
17351 #define X(f) p##f = (void*)GetProcAddress(hKernel32, #f)
17352     X(ActivateActCtx);
17353     X(CreateActCtxW);
17354     X(DeactivateActCtx);
17355     X(GetCurrentActCtx);
17356     X(QueryActCtxW);
17357     X(ReleaseActCtx);
17358 #undef X
17359 }
17360 
17361 #ifndef __REACTOS__
17362 START_TEST(msg)
17363 {
17364     char **test_argv;
17365     BOOL ret;
17366     BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
17367     HMODULE hModuleImm32;
17368     BOOL (WINAPI *pImmDisableIME)(DWORD);
17369     int argc;
17370 
17371     init_funcs();
17372 
17373     argc = winetest_get_mainargs( &test_argv );
17374     if (argc >= 3)
17375     {
17376         unsigned int arg;
17377         /* Child process. */
17378         sscanf (test_argv[2], "%d", (unsigned int *) &arg);
17379         do_wait_idle_child( arg );
17380         return;
17381     }
17382 
17383     InitializeCriticalSection( &sequence_cs );
17384     init_procs();
17385 
17386     hModuleImm32 = LoadLibraryA("imm32.dll");
17387     if (hModuleImm32) {
17388         pImmDisableIME = (void *)GetProcAddress(hModuleImm32, "ImmDisableIME");
17389         if (pImmDisableIME)
17390             pImmDisableIME(0);
17391     }
17392     pImmDisableIME = NULL;
17393     FreeLibrary(hModuleImm32);
17394 
17395     if (!RegisterWindowClasses()) assert(0);
17396 
17397     if (pSetWinEventHook)
17398     {
17399         hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
17400                                        GetModuleHandleA(0), win_event_proc,
17401                                        0, GetCurrentThreadId(),
17402                                        WINEVENT_INCONTEXT);
17403         if (pIsWinEventHookInstalled && hEvent_hook)
17404 	{
17405 	    UINT event;
17406 	    for (event = EVENT_MIN; event <= EVENT_MAX; event++)
17407 		ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
17408 	}
17409     }
17410     if (!hEvent_hook) win_skip( "no win event hook support\n" );
17411 
17412     cbt_hook_thread_id = GetCurrentThreadId();
17413     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
17414     if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
17415 
17416     test_winevents();
17417 
17418     /* Fix message sequences before removing 4 lines below */
17419     if (pUnhookWinEvent && hEvent_hook)
17420     {
17421         ret = pUnhookWinEvent(hEvent_hook);
17422         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
17423         pUnhookWinEvent = 0;
17424     }
17425     hEvent_hook = 0;
17426 
17427     test_SendMessage_other_thread(1);
17428     test_SendMessage_other_thread(2);
17429     test_InSendMessage();
17430     test_SetFocus();
17431     test_SetParent();
17432     test_PostMessage();
17433     test_broadcast();
17434     test_ShowWindow();
17435     test_PeekMessage();
17436     test_PeekMessage2();
17437     test_PeekMessage3();
17438     test_WaitForInputIdle( test_argv[0] );
17439     test_scrollwindowex();
17440     test_messages();
17441     test_setwindowpos();
17442     test_showwindow();
17443     invisible_parent_tests();
17444     test_mdi_messages();
17445     test_button_messages();
17446     test_autoradio_BM_CLICK();
17447     test_autoradio_kbd_move();
17448     test_static_messages();
17449     test_listbox_messages();
17450     test_combobox_messages();
17451     test_wmime_keydown_message();
17452     test_paint_messages();
17453     test_interthread_messages();
17454     test_message_conversion();
17455     test_accelerators();
17456     test_timers();
17457     test_timers_no_wnd();
17458     test_timers_exceptions();
17459     if (hCBT_hook)
17460     {
17461         test_set_hook();
17462         test_recursive_hook();
17463     }
17464     test_DestroyWindow();
17465     test_DispatchMessage();
17466     test_SendMessageTimeout();
17467     test_edit_messages();
17468     test_quit_message();
17469     test_notify_message();
17470     test_SetActiveWindow();
17471 
17472     if (!pTrackMouseEvent)
17473         win_skip("TrackMouseEvent is not available\n");
17474     else
17475         test_TrackMouseEvent();
17476 
17477     test_SetWindowRgn();
17478     test_sys_menu();
17479     test_dialog_messages();
17480     test_EndDialog();
17481     test_nullCallback();
17482     test_dbcs_wm_char();
17483     test_unicode_wm_char();
17484     test_menu_messages();
17485     test_paintingloop();
17486     test_defwinproc();
17487     test_clipboard_viewers();
17488     test_keyflags();
17489     test_hotkey();
17490     test_layered_window();
17491     test_TrackPopupMenu();
17492     test_TrackPopupMenuEmpty();
17493     test_DoubleSetCapture();
17494     /* keep it the last test, under Windows it tends to break the tests
17495      * which rely on active/foreground windows being correct.
17496      */
17497     test_SetForegroundWindow();
17498 
17499     UnhookWindowsHookEx(hCBT_hook);
17500     if (pUnhookWinEvent && hEvent_hook)
17501     {
17502 	ret = pUnhookWinEvent(hEvent_hook);
17503 	ok( ret, "UnhookWinEvent error %d\n", GetLastError());
17504 	SetLastError(0xdeadbeef);
17505 	ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
17506 	ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
17507 	   GetLastError() == 0xdeadbeef, /* Win9x */
17508            "unexpected error %d\n", GetLastError());
17509     }
17510     DeleteCriticalSection( &sequence_cs );
17511 }
17512 #endif /* __REACTOS__ */
17513 
17514 static void init_tests()
17515 {
17516     HMODULE hModuleImm32;
17517     BOOL (WINAPI *pImmDisableIME)(DWORD);
17518 
17519     init_funcs();
17520 
17521     InitializeCriticalSection( &sequence_cs );
17522     init_procs();
17523 
17524     hModuleImm32 = LoadLibraryA("imm32.dll");
17525     if (hModuleImm32) {
17526         pImmDisableIME = (void *)GetProcAddress(hModuleImm32, "ImmDisableIME");
17527         if (pImmDisableIME)
17528             pImmDisableIME(0);
17529     }
17530     pImmDisableIME = NULL;
17531     FreeLibrary(hModuleImm32);
17532 
17533     if (!RegisterWindowClasses()) assert(0);
17534 
17535     cbt_hook_thread_id = GetCurrentThreadId();
17536     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
17537     if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
17538 }
17539 
17540 static void cleanup_tests()
17541 {
17542     BOOL ret;
17543     UnhookWindowsHookEx(hCBT_hook);
17544     if (pUnhookWinEvent && hEvent_hook)
17545     {
17546         ret = pUnhookWinEvent(hEvent_hook);
17547         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
17548         SetLastError(0xdeadbeef);
17549         ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
17550         ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
17551            GetLastError() == 0xdeadbeef, /* Win9x */
17552            "unexpected error %d\n", GetLastError());
17553     }
17554     DeleteCriticalSection( &sequence_cs );
17555 
17556 }
17557 
17558 START_TEST(msg_queue)
17559 {
17560     int argc;
17561     char **test_argv;
17562     argc = winetest_get_mainargs( &test_argv );
17563     if (argc >= 3)
17564     {
17565         unsigned int arg;
17566         /* Child process. */
17567         sscanf (test_argv[2], "%d", (unsigned int *) &arg);
17568         do_wait_idle_child( arg );
17569         return;
17570     }
17571 
17572     init_tests();
17573     test_SendMessage_other_thread(1);
17574     test_SendMessage_other_thread(2);
17575     test_InSendMessage();
17576     test_PostMessage();
17577     test_broadcast();
17578     test_PeekMessage();
17579     test_PeekMessage2();
17580     test_PeekMessage3();
17581     test_interthread_messages();
17582     test_DispatchMessage();
17583     test_SendMessageTimeout();
17584     test_quit_message();
17585     test_notify_message();
17586     test_WaitForInputIdle( test_argv[0] );
17587     test_DestroyWindow();
17588     cleanup_tests();
17589 }
17590 
17591 START_TEST(msg_messages)
17592 {
17593     init_tests();
17594     test_message_conversion();
17595     test_messages();
17596     test_wmime_keydown_message();
17597     test_nullCallback();
17598     test_dbcs_wm_char();
17599     test_unicode_wm_char();
17600     test_defwinproc();
17601     cleanup_tests();
17602 }
17603 
17604 START_TEST(msg_focus)
17605 {
17606     init_tests();
17607 
17608     test_SetFocus();
17609 
17610     /* HACK: For some reason the tests fail on Windows if run consecutively.
17611      * Putting these in between helps, and is essentially what happens in the
17612      * "normal" msg test. */
17613     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
17614     flush_events();
17615 
17616     test_SetActiveWindow();
17617 
17618     /* HACK */
17619     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
17620     flush_events();
17621 
17622     test_DoubleSetCapture();
17623 
17624     /* keep it the last test, under Windows it tends to break the tests
17625      * which rely on active/foreground windows being correct.
17626      */
17627     test_SetForegroundWindow();
17628     cleanup_tests();
17629 }
17630 
17631 START_TEST(msg_winpos)
17632 {
17633     init_tests();
17634     test_SetParent();
17635     test_ShowWindow();
17636     test_setwindowpos();
17637     test_showwindow();
17638     test_SetWindowRgn();
17639     invisible_parent_tests();
17640     cleanup_tests();
17641 }
17642 
17643 START_TEST(msg_paint)
17644 {
17645     init_tests();
17646     test_scrollwindowex();
17647     test_paint_messages();
17648 #ifdef __REACTOS__
17649     if (!winetest_interactive &&
17650         !strcmp(winetest_platform, "windows"))
17651     {
17652         skip("ROSTESTS-185: Skipping user32_winetest:msg_paint test_paintingloop because it hangs on WHS-Testbot. Set winetest_interactive to run it anyway.\n");
17653     }
17654     else
17655 #endif
17656     test_paintingloop();
17657     cleanup_tests();
17658 }
17659 
17660 START_TEST(msg_input)
17661 {
17662     init_tests();
17663     test_accelerators();
17664     if (!pTrackMouseEvent)
17665         win_skip("TrackMouseEvent is not available\n");
17666     else
17667         test_TrackMouseEvent();
17668 
17669     test_keyflags();
17670     test_hotkey();
17671     cleanup_tests();
17672 }
17673 
17674 START_TEST(msg_timer)
17675 {
17676     init_tests();
17677     test_timers();
17678     test_timers_no_wnd();
17679     test_timers_exceptions();
17680     cleanup_tests();
17681 }
17682 
17683 typedef BOOL (WINAPI *IS_WINEVENT_HOOK_INSTALLED)(DWORD);
17684 
17685 START_TEST(msg_hook)
17686 {
17687 //    HMODULE user32 = GetModuleHandleA("user32.dll");
17688 //    IS_WINEVENT_HOOK_INSTALLED pIsWinEventHookInstalled = (IS_WINEVENT_HOOK_INSTALLED)GetProcAddress(user32, "IsWinEventHookInstalled");
17689     BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
17690 
17691     init_tests();
17692 
17693     if (pSetWinEventHook)
17694     {
17695         hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
17696                                        GetModuleHandleA(0), win_event_proc,
17697                                        0, GetCurrentThreadId(),
17698                                        WINEVENT_INCONTEXT);
17699         if (pIsWinEventHookInstalled && hEvent_hook)
17700         {
17701             UINT event;
17702             for (event = EVENT_MIN; event <= EVENT_MAX; event++)
17703                 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
17704         }
17705     }
17706     if (!hEvent_hook) win_skip( "no win event hook support\n" );
17707 
17708     test_winevents();
17709 
17710     /* Fix message sequences before removing 4 lines below */
17711     if (pUnhookWinEvent && hEvent_hook)
17712     {
17713         BOOL ret;
17714         ret = pUnhookWinEvent(hEvent_hook);
17715         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
17716         pUnhookWinEvent = 0;
17717     }
17718     hEvent_hook = 0;
17719     if (hCBT_hook)
17720     {
17721         test_set_hook();
17722         test_recursive_hook();
17723     }
17724     cleanup_tests();
17725 }
17726 
17727 START_TEST(msg_menu)
17728 {
17729     init_tests();
17730     test_sys_menu();
17731     test_menu_messages();
17732     test_TrackPopupMenu();
17733     test_TrackPopupMenuEmpty();
17734     cleanup_tests();
17735 }
17736 
17737 START_TEST(msg_mdi)
17738 {
17739     init_tests();
17740     test_mdi_messages();
17741     cleanup_tests();
17742 }
17743 
17744 START_TEST(msg_controls)
17745 {
17746     init_tests();
17747     test_button_messages();
17748     test_autoradio_BM_CLICK();
17749     test_autoradio_kbd_move();
17750     test_static_messages();
17751     test_listbox_messages();
17752     test_combobox_messages();
17753     test_edit_messages();
17754     cleanup_tests();
17755 }
17756 
17757 START_TEST(msg_layered_window)
17758 {
17759     init_tests();
17760     test_layered_window();
17761     cleanup_tests();
17762 }
17763 
17764 START_TEST(msg_dialog)
17765 {
17766     init_tests();
17767     test_dialog_messages();
17768     test_EndDialog();
17769     cleanup_tests();
17770 }
17771 
17772 START_TEST(msg_clipboard)
17773 {
17774     init_tests();
17775     test_clipboard_viewers();
17776     cleanup_tests();
17777 }
17778