1 /*
2  * Unit tests for window message handling
3  *
4  * Copyright 1999 Ove Kaaven
5  * Copyright 2003 Dimitrie O. Paun
6  * Copyright 2004,2005,2016 Dmitry Timoshkov
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22 
23 #include <assert.h>
24 #include <limits.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "winuser.h"
32 #include "winnls.h"
33 #include "dbt.h"
34 
35 #include "wine/test.h"
36 
37 #define MDI_FIRST_CHILD_ID 2004
38 
39 /* undocumented SWP flags - from SDK 3.1 */
40 #define SWP_NOCLIENTSIZE	0x0800
41 #define SWP_NOCLIENTMOVE	0x1000
42 #define SWP_STATECHANGED	0x8000
43 
44 #define SW_NORMALNA	        0xCC    /* undoc. flag in MinMaximize */
45 
46 #ifndef WM_KEYF1
47 #define WM_KEYF1 0x004d
48 #endif
49 
50 #ifndef WM_SYSTIMER
51 #define WM_SYSTIMER	    0x0118
52 #endif
53 
54 #define WND_PARENT_ID		1
55 #define WND_POPUP_ID		2
56 #define WND_CHILD_ID		3
57 
58 #ifndef WM_LBTRACKPOINT
59 #define WM_LBTRACKPOINT  0x0131
60 #endif
61 
62 #ifdef __i386__
63 #define ARCH "x86"
64 #elif defined __x86_64__
65 #define ARCH "amd64"
66 #elif defined __arm__
67 #define ARCH "arm"
68 #elif defined __aarch64__
69 #define ARCH "arm64"
70 #else
71 #define ARCH "none"
72 #endif
73 
74 static BOOL   (WINAPI *pActivateActCtx)(HANDLE,ULONG_PTR*);
75 static HANDLE (WINAPI *pCreateActCtxW)(PCACTCTXW);
76 static BOOL   (WINAPI *pDeactivateActCtx)(DWORD,ULONG_PTR);
77 static BOOL   (WINAPI *pGetCurrentActCtx)(HANDLE *);
78 static BOOL   (WINAPI *pQueryActCtxW)(DWORD,HANDLE,void*,ULONG,void*,SIZE_T,SIZE_T*);
79 static void   (WINAPI *pReleaseActCtx)(HANDLE);
80 
81 /* encoded DRAWITEMSTRUCT into an LPARAM */
82 typedef struct
83 {
84     union
85     {
86         struct
87         {
88             UINT type    : 4;  /* ODT_* flags */
89             UINT ctl_id  : 4;  /* Control ID */
90             UINT item_id : 4;  /* Menu item ID */
91             UINT action  : 4;  /* ODA_* flags */
92             UINT state   : 16; /* ODS_* flags */
93         } item;
94         LPARAM lp;
95     } u;
96 } DRAW_ITEM_STRUCT;
97 
98 /* encoded MEASUREITEMSTRUCT into a WPARAM */
99 typedef struct
100 {
101     union
102     {
103         struct
104         {
105             UINT CtlType : 4;
106             UINT CtlID   : 4;
107             UINT itemID  : 4;
108             UINT wParam  : 20;
109         } item;
110         WPARAM wp;
111     } u;
112 } MEASURE_ITEM_STRUCT;
113 
114 static BOOL test_DestroyWindow_flag;
115 static BOOL test_context_menu;
116 static HWINEVENTHOOK hEvent_hook;
117 static HHOOK hKBD_hook;
118 static HHOOK hCBT_hook;
119 static DWORD cbt_hook_thread_id;
120 
121 static const WCHAR testWindowClassW[] =
122 { 'T','e','s','t','W','i','n','d','o','w','C','l','a','s','s','W',0 };
123 
124 static LRESULT WINAPI ParentMsgCheckProcA(HWND, UINT, WPARAM, LPARAM);
125 
126 /*
127 FIXME: add tests for these
128 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
129  WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
130  WS_THICKFRAME: thick border
131  WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
132  WS_BORDER (default for overlapped windows): single black border
133  none (default for child (and popup?) windows): no border
134 */
135 
136 typedef enum {
137     sent=0x1,
138     posted=0x2,
139     parent=0x4,
140     wparam=0x8,
141     lparam=0x10,
142     defwinproc=0x20,
143     beginpaint=0x40,
144     optional=0x80,
145     hook=0x100,
146     winevent_hook=0x200,
147     kbd_hook=0x400
148 } msg_flags_t;
149 
150 struct message {
151     UINT message;          /* the WM_* code */
152     msg_flags_t flags;     /* message props */
153     WPARAM wParam;         /* expected value of wParam */
154     LPARAM lParam;         /* expected value of lParam */
155     WPARAM wp_mask;        /* mask for wParam checks */
156     LPARAM lp_mask;        /* mask for lParam checks */
157 };
158 
159 struct recvd_message {
160     UINT message;          /* the WM_* code */
161     msg_flags_t flags;     /* message props */
162     HWND hwnd;             /* window that received the message */
163     WPARAM wParam;         /* expected value of wParam */
164     LPARAM lParam;         /* expected value of lParam */
165     int line;              /* source line where logged */
166     const char *descr;     /* description for trace output */
167     char output[512];      /* trace output */
168 };
169 
170 /* Empty message sequence */
171 static const struct message WmEmptySeq[] =
172 {
173     { 0 }
174 };
175 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
176 static const struct message WmCreateOverlappedSeq[] = {
177     { HCBT_CREATEWND, hook },
178     { WM_GETMINMAXINFO, sent },
179     { WM_NCCREATE, sent },
180     { WM_NCCALCSIZE, sent|wparam, 0 },
181     { 0x0093, sent|defwinproc|optional },
182     { 0x0094, sent|defwinproc|optional },
183     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
184     { WM_CREATE, sent },
185     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
186     { 0 }
187 };
188 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
189  * for a not visible overlapped window.
190  */
191 static const struct message WmSWP_ShowOverlappedSeq[] = {
192     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
193     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
194     { WM_NCPAINT, sent|wparam|optional, 1 },
195     { WM_GETTEXT, sent|defwinproc|optional },
196     { WM_ERASEBKGND, sent|optional },
197     { HCBT_ACTIVATE, hook },
198     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
199     { WM_NOTIFYFORMAT, sent|optional },
200     { WM_QUERYUISTATE, sent|optional },
201     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
202     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
203     { WM_ACTIVATEAPP, sent|wparam, 1 },
204     { WM_NCACTIVATE, sent },
205     { WM_GETTEXT, sent|defwinproc|optional },
206     { WM_ACTIVATE, sent|wparam, 1 },
207     { HCBT_SETFOCUS, hook },
208     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
209     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
210     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
211     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
212     { WM_GETTEXT, sent|optional },
213     { WM_NCPAINT, sent|wparam|optional, 1 },
214     { WM_GETTEXT, sent|defwinproc|optional },
215     { WM_ERASEBKGND, sent|optional },
216     /* Win9x adds SWP_NOZORDER below */
217     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
218     { WM_GETTEXT, sent|optional },
219     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
220     { WM_NCPAINT, sent|wparam|optional, 1 },
221     { WM_ERASEBKGND, sent|optional },
222     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
223     { WM_SYNCPAINT, sent|optional },
224     { WM_GETTITLEBARINFOEX, sent|optional },
225     { WM_PAINT, sent|optional },
226     { WM_NCPAINT, sent|beginpaint|optional },
227     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
228     { WM_ERASEBKGND, sent|beginpaint|optional },
229     { 0 }
230 };
231 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
232  * for a visible overlapped window.
233  */
234 static const struct message WmSWP_HideOverlappedSeq[] = {
235     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
236     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
237     { HCBT_ACTIVATE, hook|optional },
238     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
239     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
240     { WM_NCACTIVATE, sent|optional },
241     { WM_ACTIVATE, sent|optional },
242     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
243     { 0 }
244 };
245 
246 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
247  * for a visible overlapped window.
248  */
249 static const struct message WmSWP_ResizeSeq[] = {
250     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
251     { WM_GETMINMAXINFO, sent|defwinproc },
252     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
253     { WM_NCPAINT, sent|optional },
254     { WM_GETTEXT, sent|defwinproc|optional },
255     { WM_ERASEBKGND, sent|optional },
256     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
257     { WM_SIZE, sent|defwinproc|optional },
258     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
259     { WM_NCPAINT, sent|optional },
260     { WM_GETTEXT, sent|defwinproc|optional },
261     { WM_ERASEBKGND, sent|optional },
262     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
263     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
264     { 0 }
265 };
266 
267 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
268  * for a visible popup window.
269  */
270 static const struct message WmSWP_ResizePopupSeq[] = {
271     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
272     { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* Win9x */
273     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
274     { WM_NCPAINT, sent|optional },
275     { WM_GETTEXT, sent|defwinproc|optional },
276     { WM_ERASEBKGND, sent|optional },
277     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
278     { WM_SIZE, sent|defwinproc|wparam|optional, SIZE_RESTORED },
279     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
280     { WM_NCPAINT, sent|optional },
281     { WM_GETTEXT, sent|defwinproc|optional },
282     { WM_ERASEBKGND, sent|optional },
283     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
284     { 0 }
285 };
286 
287 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE)
288  * for a visible overlapped window.
289  */
290 static const struct message WmSWP_MoveSeq[] = {
291     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE },
292     { WM_NCPAINT, sent|optional },
293     { WM_GETTEXT, sent|defwinproc|optional },
294     { WM_ERASEBKGND, sent|optional },
295     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
296     { WM_MOVE, sent|defwinproc|wparam, 0 },
297     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
298     { 0 }
299 };
300 /* Resize with SetWindowPos(SWP_NOZORDER)
301  * for a visible overlapped window
302  * SWP_NOZORDER is stripped by the logging code
303  */
304 static const struct message WmSWP_ResizeNoZOrder[] = {
305     { WM_WINDOWPOSCHANGING, sent|wparam, /*SWP_NOZORDER|*/SWP_NOACTIVATE },
306     { WM_GETMINMAXINFO, sent|defwinproc },
307     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
308     { WM_NCPAINT, sent|optional },
309     { WM_GETTEXT, sent|defwinproc|optional },
310     { WM_ERASEBKGND, sent|optional },
311     { WM_WINDOWPOSCHANGED, sent|wparam|optional, /*SWP_NOZORDER|*/SWP_NOACTIVATE, 0,
312       SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
313     { WM_MOVE, sent|defwinproc|optional },
314     { WM_SIZE, sent|defwinproc|optional },
315     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
316     { WM_NCPAINT, sent|optional }, /* Win9x doesn't send it */
317     { WM_GETTEXT, sent|defwinproc|optional }, /* Win9x doesn't send it */
318     { WM_ERASEBKGND, sent|optional }, /* Win9x doesn't send it */
319     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
320     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
321     { 0 }
322 };
323 
324 /* Switch visible mdi children */
325 static const struct message WmSwitchChild[] = {
326     /* Switch MDI child */
327     { WM_MDIACTIVATE, sent },/* in the MDI client */
328     { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 1st MDI child */
329     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
330     { WM_CHILDACTIVATE, sent },/* in the 1st MDI child */
331     /* Deactivate 2nd MDI child */
332     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
333     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
334     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
335     /* Preparing for maximize and maximize the 1st MDI child */
336     { WM_GETMINMAXINFO, sent|defwinproc }, /* in the 1st MDI child */
337     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED }, /* in the 1st MDI child */
338     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
339     { WM_CHILDACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
340     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 1st MDI child */
341     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, /* in the 1st MDI child */
342     /* Lock redraw 2nd MDI child */
343     { WM_SETREDRAW, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
344     { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
345     /* Restore 2nd MDI child */
346     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },/* in the 2nd MDI child */
347     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
348     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
349     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 2nd MDI child */
350     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, /* in the 2nd MDI child */
351     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
352     /* Redraw 2nd MDI child */
353     { WM_SETREDRAW, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
354     /* Redraw MDI frame */
355     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },/* in MDI frame */
356     { WM_NCCALCSIZE, sent|wparam, 1 },/* in MDI frame */
357     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in MDI frame */
358     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in MDI frame */
359     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
360     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
361     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
362     { HCBT_SETFOCUS, hook },
363     { WM_KILLFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
364     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },/* in the 1st MDI child */
365     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
366     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
367     { WM_SETFOCUS, sent },/* in the MDI client */
368     { HCBT_SETFOCUS, hook },
369     { WM_KILLFOCUS, sent },/* in the MDI client */
370     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
371     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, /* in the 1st MDI child */
372     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
373     { WM_SETFOCUS, sent|defwinproc }, /* in the 1st MDI child */
374     { WM_MDIACTIVATE, sent|defwinproc },/* in the 1st MDI child */
375     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* in the 1st MDI child */
376     { 0 }
377 };
378 
379 /* Switch visible not maximized mdi children */
380 static const struct message WmSwitchNotMaximizedChild[] = {
381     /* Switch not maximized MDI child */
382     { WM_MDIACTIVATE, sent },/* in the MDI client */
383     { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 2nd MDI child */
384     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
385     { WM_CHILDACTIVATE, sent },/* in the 2nd MDI child */
386     /* Deactivate 1st MDI child */
387     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
388     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
389     /* Activate 2nd MDI child */
390     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE}, /* in the 2nd MDI child */
391     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 2nd MDI child */
392     { HCBT_SETFOCUS, hook }, /* in the 1st MDI child */
393     { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
394     { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
395     { WM_IME_SETCONTEXT, sent|optional }, /* in the  MDI client */
396     { WM_SETFOCUS, sent, 0 }, /* in the  MDI client */
397     { HCBT_SETFOCUS, hook },
398     { WM_KILLFOCUS, sent }, /* in the  MDI client */
399     { WM_IME_SETCONTEXT, sent|optional }, /* in the  MDI client */
400     { WM_IME_SETCONTEXT, sent|defwinproc|optional  }, /* in the 1st MDI child */
401     { WM_SETFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
402     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
403     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in the 2nd MDI child */
404     { 0 }
405 };
406 
407 
408 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
409                 SWP_NOZORDER|SWP_FRAMECHANGED)
410  * for a visible overlapped window with WS_CLIPCHILDREN style set.
411  */
412 static const struct message WmSWP_FrameChanged_clip[] = {
413     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
414     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
415     { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
416     { WM_GETTEXT, sent|parent|defwinproc|optional },
417     { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
418     { WM_NCPAINT, sent }, /* wparam != 1 */
419     { WM_ERASEBKGND, sent },
420     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
421     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
422     { WM_PAINT, sent },
423     { 0 }
424 };
425 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|
426                 SWP_NOZORDER|SWP_FRAMECHANGED)
427  * for a visible overlapped window.
428  */
429 static const struct message WmSWP_FrameChangedDeferErase[] = {
430     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
431     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
432     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
433     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
434     { WM_PAINT, sent|parent|optional },
435     { WM_NCPAINT, sent|beginpaint|parent|optional }, /* wparam != 1 */
436     { WM_GETTEXT, sent|beginpaint|parent|defwinproc|optional },
437     { WM_PAINT, sent },
438     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
439     { WM_ERASEBKGND, sent|beginpaint|optional },
440     { 0 }
441 };
442 
443 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
444                 SWP_NOZORDER|SWP_FRAMECHANGED)
445  * for a visible overlapped window without WS_CLIPCHILDREN style set.
446  */
447 static const struct message WmSWP_FrameChanged_noclip[] = {
448     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
449     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
450     { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
451     { WM_GETTEXT, sent|parent|defwinproc|optional },
452     { WM_ERASEBKGND, sent|parent|optional },
453     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
454     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
455     { WM_PAINT, sent },
456     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
457     { WM_ERASEBKGND, sent|beginpaint|optional },
458     { 0 }
459 };
460 
461 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
462 static const struct message WmShowOverlappedSeq[] = {
463     { WM_SHOWWINDOW, sent|wparam, 1 },
464     { WM_NCPAINT, sent|wparam|optional, 1 },
465     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
466     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
467     { WM_NCPAINT, sent|wparam|optional, 1 },
468     { WM_GETTEXT, sent|defwinproc|optional },
469     { WM_ERASEBKGND, sent|optional },
470     { HCBT_ACTIVATE, hook|optional },
471     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
472     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
473     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
474     { WM_NCPAINT, sent|wparam|optional, 1 },
475     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
476     { WM_NCACTIVATE, sent|wparam|optional, 1 },
477     { WM_GETTEXT, sent|defwinproc|optional },
478     { WM_ACTIVATE, sent|wparam|optional, 1 },
479     { HCBT_SETFOCUS, hook|optional },
480     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
481     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
482     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
483     { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
484     { WM_GETTEXT, sent|optional },
485     { WM_NCPAINT, sent|wparam|optional, 1 },
486     { WM_GETTEXT, sent|defwinproc|optional },
487     { WM_ERASEBKGND, sent|optional },
488     /* Win9x adds SWP_NOZORDER below */
489     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
490     { WM_NCCALCSIZE, sent|optional },
491     { WM_GETTEXT, sent|optional },
492     { WM_NCPAINT, sent|optional },
493     { WM_ERASEBKGND, sent|optional },
494     { WM_SYNCPAINT, sent|optional },
495 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
496        * messages. Does that mean that CreateWindow doesn't set initial
497        * window dimensions for overlapped windows?
498        */
499     { WM_SIZE, sent },
500     { WM_MOVE, sent },
501 #endif
502     { WM_PAINT, sent|optional },
503     { WM_NCPAINT, sent|beginpaint|optional },
504     { 0 }
505 };
506 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible overlapped window */
507 static const struct message WmShowMaxOverlappedSeq[] = {
508     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
509     { WM_GETMINMAXINFO, sent },
510     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
511     { WM_GETMINMAXINFO, sent|defwinproc },
512     { WM_NCCALCSIZE, sent|wparam, TRUE },
513     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
514     { HCBT_ACTIVATE, hook|optional },
515     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
516     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
517     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
518     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
519     { WM_NCACTIVATE, sent|wparam|optional, 1 },
520     { WM_GETTEXT, sent|defwinproc|optional },
521     { WM_ACTIVATE, sent|wparam|optional, 1 },
522     { HCBT_SETFOCUS, hook|optional },
523     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
524     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
525     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
526     { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
527     { WM_GETTEXT, sent|optional },
528     { WM_NCPAINT, sent|wparam|optional, 1 },
529     { WM_GETTEXT, sent|defwinproc|optional },
530     { WM_ERASEBKGND, sent|optional },
531     /* Win9x adds SWP_NOZORDER below */
532     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
533     { WM_MOVE, sent|defwinproc },
534     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
535     { WM_GETTEXT, sent|optional },
536     { WM_NCCALCSIZE, sent|optional },
537     { WM_NCPAINT, sent|optional },
538     { WM_ERASEBKGND, sent|optional },
539     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
540     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
541     { WM_SYNCPAINT, sent|optional },
542     { WM_GETTITLEBARINFOEX, sent|optional },
543     { WM_PAINT, sent|optional },
544     { WM_NCPAINT, sent|beginpaint|optional },
545     { WM_ERASEBKGND, sent|beginpaint|optional },
546     { 0 }
547 };
548 /* ShowWindow(SW_RESTORE) for a not visible maximized overlapped window */
549 static const struct message WmShowRestoreMaxOverlappedSeq[] = {
550     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
551     { WM_GETTEXT, sent|optional },
552     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
553     { WM_GETMINMAXINFO, sent|defwinproc },
554     { WM_NCCALCSIZE, sent|wparam, TRUE },
555     { WM_NCPAINT, sent|optional },
556     { WM_GETTEXT, sent|defwinproc|optional },
557     { WM_ERASEBKGND, sent|optional },
558     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
559     { WM_MOVE, sent|defwinproc|optional },
560     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
561     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
562     { WM_NCPAINT, sent|optional },
563     { WM_ERASEBKGND, sent|optional },
564     { WM_PAINT, sent|optional },
565     { WM_GETTITLEBARINFOEX, sent|optional },
566     { WM_NCPAINT, sent|beginpaint|optional },
567     { WM_ERASEBKGND, sent|beginpaint|optional },
568     { WM_SYNCPAINT, sent|optional },
569     { 0 }
570 };
571 /* ShowWindow(SW_RESTORE) for a not visible minimized overlapped window */
572 static const struct message WmShowRestoreMinOverlappedSeq[] = {
573     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
574     { WM_QUERYOPEN, sent|optional },
575     { WM_GETTEXT, sent|optional },
576     { WM_NCACTIVATE, sent|wparam|optional, 1 },
577     { WM_WINDOWPOSCHANGING, sent|optional }, /* SWP_NOSIZE|SWP_NOMOVE */
578     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
579     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
580     { WM_MOVE, sent|optional },
581     { WM_SIZE, sent|wparam|optional, SIZE_RESTORED },
582     { WM_GETTEXT, sent|optional },
583     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED|SWP_NOCOPYBITS },
584     { WM_GETMINMAXINFO, sent|defwinproc|optional },
585     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
586     { HCBT_ACTIVATE, hook|optional },
587     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
588     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
589     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
590     { WM_NCACTIVATE, sent|wparam|optional, 1 },
591     { WM_GETTEXT, sent|defwinproc|optional },
592     { WM_ACTIVATE, sent|wparam|optional, 1 },
593     { HCBT_SETFOCUS, hook|optional },
594     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
595     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
596     { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
597     { WM_GETTEXT, sent|optional },
598     { WM_NCPAINT, sent|wparam|optional, 1 },
599     { WM_GETTEXT, sent|defwinproc|optional },
600     { WM_ERASEBKGND, sent },
601     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_STATECHANGED|SWP_FRAMECHANGED|SWP_NOCOPYBITS },
602     { WM_MOVE, sent|defwinproc },
603     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
604     { HCBT_SETFOCUS, hook|optional },
605     { WM_SETFOCUS, sent|wparam|optional, 0 },
606     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
607     { WM_NCPAINT, sent|wparam|optional, 1 },
608     { WM_ERASEBKGND, sent|optional },
609     { HCBT_SETFOCUS, hook|optional },
610     { WM_SETFOCUS, sent|wparam|optional, 0 },
611     { WM_ACTIVATE, sent|wparam, 1 },
612     { WM_GETTEXT, sent|optional },
613     { WM_PAINT, sent|optional },
614     { WM_GETTITLEBARINFOEX, sent|optional },
615     { WM_NCPAINT, sent|beginpaint|optional },
616     { WM_ERASEBKGND, sent|beginpaint|optional },
617     { 0 }
618 };
619 /* ShowWindow(SW_SHOWMINIMIZED) for a not visible overlapped window */
620 static const struct message WmShowMinOverlappedSeq[] = {
621     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
622     { HCBT_SETFOCUS, hook|optional },
623     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
624     { WM_KILLFOCUS, sent|optional },
625     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
626     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
627     { WM_GETTEXT, sent|optional },
628     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCOPYBITS|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
629     { WM_GETMINMAXINFO, sent|defwinproc },
630     { WM_NCCALCSIZE, sent|wparam, TRUE },
631     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
632     { WM_NCPAINT, sent|optional },
633     { WM_GETTEXT, sent|defwinproc|optional },
634     { WM_WINDOWPOSCHANGED, sent },
635     { WM_MOVE, sent|defwinproc },
636     { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
637     { WM_NCCALCSIZE, sent|optional },
638     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
639     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
640     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
641     { WM_NCACTIVATE, sent|wparam|optional, 0 },
642     { WM_GETTEXT, sent|defwinproc|optional },
643     { WM_ACTIVATE, sent|optional },
644     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
645 
646     /* Vista sometimes restores the window right away... */
647     { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
648     { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
649     { HCBT_MINMAX, hook|optional|lparam, 0, SW_RESTORE },
650     { WM_QUERYOPEN, sent|optional },
651     { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
652     { WM_GETMINMAXINFO, sent|optional|defwinproc },
653     { WM_NCCALCSIZE, sent|optional|wparam, TRUE },
654     { HCBT_ACTIVATE, hook|optional },
655     { WM_ACTIVATEAPP, sent|optional|wparam, 1 },
656     { WM_NCACTIVATE, sent|optional },
657     { WM_GETTEXT, sent|optional },
658     { WM_ACTIVATE, sent|optional|wparam, 1 },
659     { HCBT_SETFOCUS, hook|optional },
660     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
661     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
662     { WM_SETFOCUS, sent|optional },
663     { WM_NCPAINT, sent|optional },
664     { WM_GETTEXT, sent|defwinproc|optional },
665     { WM_ERASEBKGND, sent|optional },
666     { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
667     { WM_MOVE, sent|defwinproc|optional },
668     { WM_SIZE, sent|defwinproc|optional|wparam, SIZE_RESTORED },
669     { WM_ACTIVATE, sent|optional|wparam, 1 },
670     { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
671     { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
672 
673     { WM_PAINT, sent|optional },
674     { WM_NCPAINT, sent|beginpaint|optional },
675     { WM_ERASEBKGND, sent|beginpaint|optional },
676     { 0 }
677 };
678 /* ShowWindow(SW_HIDE) for a visible overlapped window */
679 static const struct message WmHideOverlappedSeq[] = {
680     { WM_SHOWWINDOW, sent|wparam, 0 },
681     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
682     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
683     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
684     { WM_SIZE, sent|optional }, /* XP doesn't send it */
685     { WM_MOVE, sent|optional }, /* XP doesn't send it */
686     { WM_NCACTIVATE, sent|wparam|optional, 0 },
687     { WM_ACTIVATE, sent|wparam|optional, 0 },
688     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
689     { HCBT_SETFOCUS, hook|optional },
690     { WM_KILLFOCUS, sent|wparam|optional, 0 },
691     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
692     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
693     { 0 }
694 };
695 /* DestroyWindow for a visible overlapped window */
696 static const struct message WmDestroyOverlappedSeq[] = {
697     { HCBT_DESTROYWND, hook },
698     { 0x0090, sent|optional },
699     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
700     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
701     { 0x0090, sent|optional },
702     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
703     { WM_NCACTIVATE, sent|optional|wparam, 0 },
704     { WM_ACTIVATE, sent|optional },
705     { WM_ACTIVATEAPP, sent|optional|wparam, 0 },
706     { WM_KILLFOCUS, sent|optional|wparam, 0 },
707     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
708     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
709     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
710     { WM_DESTROY, sent },
711     { WM_NCDESTROY, sent },
712     { 0 }
713 };
714 /* CreateWindow(WS_MAXIMIZE|WS_VISIBLE) for popup window */
715 static const struct message WmCreateMaxPopupSeq[] = {
716     { HCBT_CREATEWND, hook },
717     { WM_NCCREATE, sent },
718     { WM_NCCALCSIZE, sent|wparam, 0 },
719     { WM_CREATE, sent },
720     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
721     { WM_SIZE, sent|wparam, SIZE_RESTORED },
722     { WM_MOVE, sent },
723     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
724     { WM_GETMINMAXINFO, sent },
725     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
726     { WM_NCCALCSIZE, sent|wparam, TRUE },
727     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
728     { WM_MOVE, sent|defwinproc },
729     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
730     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
731     { WM_SHOWWINDOW, sent|wparam, 1 },
732     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
733     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
734     { HCBT_ACTIVATE, hook },
735     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
736     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
737     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
738     { WM_NCPAINT, sent|wparam|optional, 1 },
739     { WM_ERASEBKGND, sent|optional },
740     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_NOMOVE|SWP_NOSIZE },
741     { WM_ACTIVATEAPP, sent|wparam, 1 },
742     { WM_NCACTIVATE, sent },
743     { WM_ACTIVATE, sent|wparam, 1 },
744     { HCBT_SETFOCUS, hook },
745     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
746     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
747     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
748     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
749     { WM_GETTEXT, sent|optional },
750     { WM_SYNCPAINT, sent|wparam|optional, 4 },
751     { WM_NCPAINT, sent|wparam|optional, 1 },
752     { WM_ERASEBKGND, sent|optional },
753     { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
754     { WM_ERASEBKGND, sent|defwinproc|optional },
755     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
756     { 0 }
757 };
758 /* CreateWindow(WS_MAXIMIZE) for popup window, not initially visible */
759 static const struct message WmCreateInvisibleMaxPopupSeq[] = {
760     { HCBT_CREATEWND, hook },
761     { WM_NCCREATE, sent },
762     { WM_NCCALCSIZE, sent|wparam, 0 },
763     { WM_CREATE, sent },
764     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
765     { WM_SIZE, sent|wparam, SIZE_RESTORED },
766     { WM_MOVE, sent },
767     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
768     { WM_GETMINMAXINFO, sent },
769     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED  },
770     { WM_NCCALCSIZE, sent|wparam, TRUE },
771     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
772     { WM_MOVE, sent|defwinproc },
773     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
774     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
775     { 0 }
776 };
777 /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */
778 static const struct message WmShowMaxPopupResizedSeq[] = {
779     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
780     { WM_GETMINMAXINFO, sent },
781     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
782     { WM_NCCALCSIZE, sent|wparam, TRUE },
783     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
784     { HCBT_ACTIVATE, hook },
785     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
786     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
787     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
788     { WM_NCPAINT, sent|wparam|optional, 1 },
789     { WM_ERASEBKGND, sent|optional },
790     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
791     { WM_ACTIVATEAPP, sent|wparam, 1 },
792     { WM_NCACTIVATE, sent },
793     { WM_ACTIVATE, sent|wparam, 1 },
794     { HCBT_SETFOCUS, hook },
795     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
796     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
797     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
798     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
799     { WM_GETTEXT, sent|optional },
800     { WM_NCPAINT, sent|wparam|optional, 1 },
801     { WM_ERASEBKGND, sent|optional },
802     { WM_WINDOWPOSCHANGED, sent },
803     /* WinNT4.0 sends WM_MOVE */
804     { WM_MOVE, sent|defwinproc|optional },
805     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
806     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
807     { 0 }
808 };
809 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible popup window */
810 static const struct message WmShowMaxPopupSeq[] = {
811     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
812     { WM_GETMINMAXINFO, sent },
813     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
814     { WM_NCCALCSIZE, sent|wparam, TRUE },
815     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
816     { HCBT_ACTIVATE, hook },
817     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
818     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
819     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
820     { WM_NCPAINT, sent|wparam|optional, 1 },
821     { WM_ERASEBKGND, sent|optional },
822     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOMOVE|SWP_NOSIZE },
823     { WM_ACTIVATEAPP, sent|wparam, 1 },
824     { WM_NCACTIVATE, sent },
825     { WM_ACTIVATE, sent|wparam, 1 },
826     { HCBT_SETFOCUS, hook },
827     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
828     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
829     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
830     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
831     { WM_GETTEXT, sent|optional },
832     { WM_SYNCPAINT, sent|wparam|optional, 4 },
833     { WM_NCPAINT, sent|wparam|optional, 1 },
834     { WM_ERASEBKGND, sent|optional },
835     { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
836     { WM_ERASEBKGND, sent|defwinproc|optional },
837     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE },
838     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
839     { WM_SIZE, sent|defwinproc|optional },
840     { 0 }
841 };
842 /* CreateWindow(WS_VISIBLE) for popup window */
843 static const struct message WmCreatePopupSeq[] = {
844     { HCBT_CREATEWND, hook },
845     { WM_NCCREATE, sent },
846     { WM_NCCALCSIZE, sent|wparam, 0 },
847     { WM_CREATE, sent },
848     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
849     { WM_SIZE, sent|wparam, SIZE_RESTORED },
850     { WM_MOVE, sent },
851     { WM_SHOWWINDOW, sent|wparam, 1 },
852     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
853     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
854     { HCBT_ACTIVATE, hook },
855     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
856     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
857     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
858     { WM_NCPAINT, sent|wparam|optional, 1 },
859     { WM_ERASEBKGND, sent|optional },
860     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
861     { WM_ACTIVATEAPP, sent|wparam, 1 },
862     { WM_NCACTIVATE, sent },
863     { WM_ACTIVATE, sent|wparam, 1 },
864     { HCBT_SETFOCUS, hook },
865     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
866     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
867     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
868     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
869     { WM_GETTEXT, sent|optional },
870     { WM_SYNCPAINT, sent|wparam|optional, 4 },
871     { WM_NCPAINT, sent|wparam|optional, 1 },
872     { WM_ERASEBKGND, sent|optional },
873     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
874     { 0 }
875 };
876 /* ShowWindow(SW_SHOWMAXIMIZED) for a visible popup window */
877 static const struct message WmShowVisMaxPopupSeq[] = {
878     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
879     { WM_GETMINMAXINFO, sent },
880     { WM_GETTEXT, sent|optional },
881     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
882     { WM_GETTEXT, sent|optional },
883     { WM_NCCALCSIZE, sent|wparam, TRUE },
884     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
885     { WM_NCPAINT, sent|wparam|optional, 1 },
886     { WM_ERASEBKGND, sent|optional },
887     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
888     { WM_MOVE, sent|defwinproc },
889     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
890     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
891     { 0 }
892 };
893 /* CreateWindow (for a child popup window, not initially visible) */
894 static const struct message WmCreateChildPopupSeq[] = {
895     { HCBT_CREATEWND, hook },
896     { WM_NCCREATE, sent },
897     { WM_NCCALCSIZE, sent|wparam, 0 },
898     { WM_CREATE, sent },
899     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
900     { WM_SIZE, sent|wparam, SIZE_RESTORED },
901     { WM_MOVE, sent },
902     { 0 }
903 };
904 /* CreateWindow (for a popup window, not initially visible,
905  * which sets WS_VISIBLE in WM_CREATE handler)
906  */
907 static const struct message WmCreateInvisiblePopupSeq[] = {
908     { HCBT_CREATEWND, hook },
909     { WM_NCCREATE, sent },
910     { WM_NCCALCSIZE, sent|wparam, 0 },
911     { WM_CREATE, sent },
912     { WM_STYLECHANGING, sent },
913     { WM_STYLECHANGED, sent },
914     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
915     { WM_SIZE, sent|wparam, SIZE_RESTORED },
916     { WM_MOVE, sent },
917     { 0 }
918 };
919 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
920  * for a popup window with WS_VISIBLE style set
921  */
922 static const struct message WmShowVisiblePopupSeq_2[] = {
923     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
924     { 0 }
925 };
926 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
927  * for a popup window with WS_VISIBLE style set
928  */
929 static const struct message WmShowVisiblePopupSeq_3[] = {
930     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
931     { HCBT_ACTIVATE, hook },
932     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
933     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
934     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
935     { WM_NCACTIVATE, sent },
936     { WM_ACTIVATE, sent|wparam, 1 },
937     { HCBT_SETFOCUS, hook },
938     { WM_KILLFOCUS, sent|parent },
939     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
940     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
941     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
942     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
943     { WM_SETFOCUS, sent|defwinproc },
944     { WM_GETTEXT, sent|optional },
945     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_SHOWWINDOW },
946     { 0 }
947 };
948 /* CreateWindow (for a popup window with WS_VISIBLE style set and extreme location)
949  */
950 static const struct message WmShowPopupExtremeLocationSeq[] = {
951     { HCBT_CREATEWND, hook },
952     { WM_NCCREATE, sent },
953     { WM_NCCALCSIZE, sent|wparam, 0 },
954     { WM_CREATE, sent },
955     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
956     { WM_SIZE, sent|wparam, SIZE_RESTORED },
957     { WM_MOVE, sent },
958     { WM_SHOWWINDOW, sent|wparam, 1 },
959     { WM_WINDOWPOSCHANGING, sent },
960     { HCBT_ACTIVATE, hook },
961     { WM_WINDOWPOSCHANGING, sent|optional },
962     { WM_QUERYNEWPALETTE, sent|optional },
963     { WM_ACTIVATEAPP, sent },
964     { WM_NCACTIVATE, sent },
965     { WM_ACTIVATE, sent },
966     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
967     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
968     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
969     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
970     { HCBT_SETFOCUS, hook },
971     { WM_SETFOCUS, sent|defwinproc },
972     { WM_NCPAINT, sent|wparam, 1 },
973     { WM_ERASEBKGND, sent },
974     { WM_WINDOWPOSCHANGED, sent },
975     /* occasionally received on test machines */
976     { WM_NCPAINT, sent|optional },
977     { WM_ERASEBKGND, sent|optional },
978     { 0 }
979 };
980 /* CreateWindow (for a popup window with WS_VISIBLE style set)
981  */
982 static const struct message WmShowPopupFirstDrawSeq_1[] = {
983     { HCBT_CREATEWND, hook },
984     { WM_NCCREATE, sent },
985     { WM_NCCALCSIZE, sent|wparam, 0 },
986     { WM_CREATE, sent },
987     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
988     { WM_SIZE, sent|wparam, SIZE_RESTORED },
989     { WM_MOVE, sent },
990     { WM_SHOWWINDOW, sent|wparam, 1 },
991     { WM_WINDOWPOSCHANGING, sent },
992     { HCBT_ACTIVATE, hook },
993     { WM_WINDOWPOSCHANGING, sent|optional },
994     { WM_QUERYNEWPALETTE, sent|optional },
995     { WM_ACTIVATEAPP, sent },
996     { WM_NCACTIVATE, sent },
997     { WM_ACTIVATE, sent },
998     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
999     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1000     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1001     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1002     { HCBT_SETFOCUS, hook },
1003     { WM_SETFOCUS, sent|defwinproc },
1004     { WM_NCPAINT, sent|wparam, 1 },
1005     { WM_ERASEBKGND, sent },
1006     { WM_WINDOWPOSCHANGED, sent },
1007     { WM_PAINT, sent },
1008     /* occasionally received on test machines */
1009     { WM_NCPAINT, sent|beginpaint|optional },
1010     { WM_ERASEBKGND, sent|beginpaint|optional },
1011     { 0 }
1012 };
1013 /* CreateWindow (for a popup window that is shown with ShowWindow(SW_SHOWMAXIMIZED))
1014  */
1015 static const struct message WmShowPopupFirstDrawSeq_2[] = {
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     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1024     { WM_GETMINMAXINFO, sent },
1025     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_STATECHANGED|SWP_SHOWWINDOW|SWP_FRAMECHANGED  },
1026     { WM_NCCALCSIZE, sent|wparam, TRUE },
1027     { HCBT_ACTIVATE, hook },
1028     { WM_WINDOWPOSCHANGING, sent|optional },
1029     { WM_NCPAINT, sent|optional|wparam, 1 },
1030     { WM_ERASEBKGND, sent|optional },
1031     { WM_WINDOWPOSCHANGED, sent|optional },
1032     { WM_QUERYNEWPALETTE, sent|optional },
1033     { WM_ACTIVATEAPP, sent },
1034     { WM_NCACTIVATE, sent },
1035     { WM_ACTIVATE, sent },
1036     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1037     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1038     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1039     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1040     { HCBT_SETFOCUS, hook },
1041     { WM_SETFOCUS, sent|defwinproc },
1042     { WM_NCPAINT, sent|wparam, 1 },
1043     { WM_ERASEBKGND, sent },
1044     { WM_WINDOWPOSCHANGED, sent|optional },
1045     { WM_MOVE, sent|defwinproc },
1046     { WM_SIZE, sent|defwinproc, 0 },
1047     { WM_PAINT, sent},
1048     /* occasionally received on test machines */
1049     { WM_NCPAINT, sent|beginpaint|optional },
1050     { WM_ERASEBKGND, sent|beginpaint|optional },
1051     { 0 }
1052 };
1053 static const struct message WmFirstDrawSetWindowPosSeq1[] = {
1054     { HCBT_CREATEWND, hook },
1055     { WM_NCCREATE, sent },
1056     { WM_NCCALCSIZE, sent|wparam, 0 },
1057     { WM_CREATE, sent },
1058     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1059     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1060     { WM_MOVE, sent },
1061     { WM_WINDOWPOSCHANGING, sent },
1062     { HCBT_ACTIVATE, hook },
1063     { WM_WINDOWPOSCHANGING, sent|optional },
1064     { WM_QUERYNEWPALETTE, sent|optional },
1065     { WM_ACTIVATEAPP, sent },
1066     { WM_NCACTIVATE, sent },
1067     { WM_ACTIVATE, sent },
1068     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1069     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1070     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1071     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1072     { HCBT_SETFOCUS, hook },
1073     { WM_SETFOCUS, sent|defwinproc },
1074     { WM_NCPAINT, sent|wparam, 1 },
1075     { WM_ERASEBKGND, sent },
1076     { WM_WINDOWPOSCHANGED, sent },
1077     { WM_MOVE, sent|defwinproc },
1078     { 0 }
1079 };
1080 static const struct message WmFirstDrawSetWindowPosSeq2[] = {
1081     { HCBT_CREATEWND, hook },
1082     { WM_NCCREATE, sent },
1083     { WM_NCCALCSIZE, sent|wparam, 0 },
1084     { WM_CREATE, sent },
1085     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1086     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1087     { WM_MOVE, sent },
1088     { WM_WINDOWPOSCHANGING, sent },
1089     { HCBT_ACTIVATE, hook },
1090     { WM_QUERYNEWPALETTE, sent|optional },
1091     { WM_WINDOWPOSCHANGING, sent|optional },
1092     { WM_ACTIVATEAPP, sent },
1093     { WM_NCACTIVATE, sent },
1094     { WM_ACTIVATE, sent },
1095     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1096     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1097     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1098     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1099     { HCBT_SETFOCUS, hook },
1100     { WM_SETFOCUS, sent|defwinproc },
1101     { WM_WINDOWPOSCHANGED, sent },
1102     { WM_MOVE, sent|defwinproc },
1103     { 0 }
1104 };
1105 static const struct message WmFirstDrawSetWindowPosSeq3[] = {
1106     { HCBT_CREATEWND, hook },
1107     { WM_NCCREATE, sent },
1108     { WM_NCCALCSIZE, sent|wparam, 0 },
1109     { WM_CREATE, sent },
1110     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1111     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1112     { WM_MOVE, sent },
1113     { HCBT_ACTIVATE, hook|optional },
1114     /* Probably shouldn't happen, but not part of this test */
1115     { WM_QUERYNEWPALETTE, sent|optional },
1116     { WM_ACTIVATEAPP, sent|optional },
1117     { WM_NCACTIVATE, sent|optional },
1118     { WM_ACTIVATE, sent|optional },
1119     { HCBT_SETFOCUS, hook|optional },
1120     { WM_SETFOCUS, sent|defwinproc|optional },
1121     { 0 }
1122 };
1123 static const struct message WmFirstDrawSetWindowPosSeq4[] = {
1124     { HCBT_CREATEWND, hook },
1125     { WM_NCCREATE, sent },
1126     { WM_NCCALCSIZE, sent|wparam, 0 },
1127     { WM_CREATE, sent },
1128     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1129     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1130     { WM_MOVE, sent },
1131     { WM_WINDOWPOSCHANGING, sent },
1132     { HCBT_ACTIVATE, hook },
1133     { WM_WINDOWPOSCHANGING, sent|optional },
1134     { WM_QUERYNEWPALETTE, sent|optional },
1135     { WM_ACTIVATEAPP, sent },
1136     { WM_NCACTIVATE, sent },
1137     { WM_ACTIVATE, sent },
1138     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1139     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1140     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1141     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1142     { HCBT_SETFOCUS, hook },
1143     { WM_SETFOCUS, sent|defwinproc },
1144     { WM_NCPAINT, sent|wparam, 1 },
1145     { WM_ERASEBKGND, sent },
1146     { WM_WINDOWPOSCHANGED, sent },
1147     { 0 }
1148 };
1149 static const struct message WmFirstDrawSetWindowPosSeq5[] = {
1150     { HCBT_CREATEWND, hook },
1151     { WM_NCCREATE, sent },
1152     { WM_NCCALCSIZE, sent|wparam, 0 },
1153     { WM_CREATE, sent },
1154     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1155     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1156     { WM_MOVE, sent },
1157     { WM_WINDOWPOSCHANGING, sent },
1158     { HCBT_ACTIVATE, hook },
1159     { WM_WINDOWPOSCHANGING, sent|optional },
1160     { WM_QUERYNEWPALETTE, sent|optional },
1161     { WM_ACTIVATEAPP, sent },
1162     { WM_NCACTIVATE, sent },
1163     { WM_ACTIVATE, sent },
1164     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1165     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1166     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1167     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1168     { HCBT_SETFOCUS, hook },
1169     { WM_SETFOCUS, sent|defwinproc },
1170     { WM_WINDOWPOSCHANGED, sent },
1171     { 0 }
1172 };
1173 static const struct message WmFirstDrawChildSeq1[] = {
1174     { 0 }
1175 };
1176 static const struct message WmFirstDrawChildSeq2[] = {
1177     { WM_NCPAINT, sent|wparam, 1 },
1178     { WM_ERASEBKGND, sent },
1179     /* occasionally received on test machines */
1180     { WM_NCPAINT, sent|optional },
1181     { WM_ERASEBKGND, sent|optional },
1182     { 0 }
1183 };
1184 /* CreateWindow (for child window, not initially visible) */
1185 static const struct message WmCreateChildSeq[] = {
1186     { HCBT_CREATEWND, hook },
1187     { WM_NCCREATE, sent },
1188     /* child is inserted into parent's child list after WM_NCCREATE returns */
1189     { WM_NCCALCSIZE, sent|wparam, 0 },
1190     { WM_CREATE, sent },
1191     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1192     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1193     { WM_MOVE, sent },
1194     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1195     { 0 }
1196 };
1197 /* CreateWindow (for maximized child window, not initially visible) */
1198 static const struct message WmCreateMaximizedChildSeq[] = {
1199     { HCBT_CREATEWND, hook },
1200     { WM_NCCREATE, sent },
1201     { WM_NCCALCSIZE, sent|wparam, 0 },
1202     { WM_CREATE, sent },
1203     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1204     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1205     { WM_MOVE, sent },
1206     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1207     { WM_GETMINMAXINFO, sent },
1208     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
1209     { WM_NCCALCSIZE, sent|wparam, 1 },
1210     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1211     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1212     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1213     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1214     { 0 }
1215 };
1216 /* CreateWindow (for a child window, initially visible) */
1217 static const struct message WmCreateVisibleChildSeq[] = {
1218     { HCBT_CREATEWND, hook },
1219     { WM_NCCREATE, sent },
1220     /* child is inserted into parent's child list after WM_NCCREATE returns */
1221     { WM_NCCALCSIZE, sent|wparam, 0 },
1222     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 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     { WM_SHOWWINDOW, sent|wparam, 1 },
1229     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1230     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1231     { WM_ERASEBKGND, sent|parent|optional },
1232     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1233     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */
1234     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1235     { 0 }
1236 };
1237 /* ShowWindow(SW_SHOW) for a not visible child window */
1238 static const struct message WmShowChildSeq[] = {
1239     { WM_SHOWWINDOW, sent|wparam, 1 },
1240     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1241     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1242     { WM_ERASEBKGND, sent|parent|optional },
1243     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1244     { 0 }
1245 };
1246 /* ShowWindow(SW_HIDE) for a visible child window */
1247 static const struct message WmHideChildSeq[] = {
1248     { WM_SHOWWINDOW, sent|wparam, 0 },
1249     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1250     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1251     { WM_ERASEBKGND, sent|parent|optional },
1252     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1253     { 0 }
1254 };
1255 /* ShowWindow(SW_HIDE) for a visible child window checking all parent events*/
1256 static const struct message WmHideChildSeq2[] = {
1257     { WM_SHOWWINDOW, sent|wparam, 0 },
1258     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1259     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1260     { WM_ERASEBKGND, sent|parent|optional },
1261     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1262     { 0 }
1263 };
1264 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
1265  * for a not visible child window
1266  */
1267 static const struct message WmShowChildSeq_2[] = {
1268     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1269     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1270     { WM_CHILDACTIVATE, sent },
1271     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1272     { 0 }
1273 };
1274 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
1275  * for a not visible child window
1276  */
1277 static const struct message WmShowChildSeq_3[] = {
1278     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1279     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1280     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1281     { 0 }
1282 };
1283 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
1284  * for a visible child window with a caption
1285  */
1286 static const struct message WmShowChildSeq_4[] = {
1287     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1288     { WM_CHILDACTIVATE, sent },
1289     { 0 }
1290 };
1291 /* ShowWindow(SW_MINIMIZE) for child with invisible parent */
1292 static const struct message WmShowChildInvisibleParentSeq_1[] = {
1293     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1294     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1295     { WM_NCCALCSIZE, sent|wparam, 1 },
1296     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1297     { WM_CHILDACTIVATE, sent|optional },
1298     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1299     { WM_MOVE, sent|defwinproc },
1300     { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1301     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1302     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1303     /* FIXME: Wine creates an icon/title window while Windows doesn't */
1304     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1305     { WM_GETTEXT, sent|optional },
1306     { 0 }
1307 };
1308 /* repeated ShowWindow(SW_MINIMIZE) for child with invisible parent */
1309 static const struct message WmShowChildInvisibleParentSeq_1r[] = {
1310     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1311     { 0 }
1312 };
1313 /* ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1314 static const struct message WmShowChildInvisibleParentSeq_2[] = {
1315     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1316     { WM_GETMINMAXINFO, sent },
1317     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
1318     { WM_NCCALCSIZE, sent|wparam, 1 },
1319     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1320     { WM_CHILDACTIVATE, sent },
1321     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1322     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1323     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1324     { 0 }
1325 };
1326 /* repeated ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1327 static const struct message WmShowChildInvisibleParentSeq_2r[] = {
1328     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1329     { 0 }
1330 };
1331 /* ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1332 static const struct message WmShowChildInvisibleParentSeq_3[] = {
1333     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1334     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1335     { WM_NCCALCSIZE, sent|wparam, 1 },
1336     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1337     { WM_CHILDACTIVATE, sent },
1338     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1339     { WM_MOVE, sent|defwinproc },
1340     { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1341     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1342     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1343     /* FIXME: Wine creates an icon/title window while Windows doesn't */
1344     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1345     { WM_GETTEXT, sent|optional },
1346     { 0 }
1347 };
1348 /* repeated ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1349 static const struct message WmShowChildInvisibleParentSeq_3r[] = {
1350     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1351     { 0 }
1352 };
1353 /* ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1354 static const struct message WmShowChildInvisibleParentSeq_4[] = {
1355     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1356     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
1357     { WM_NCCALCSIZE, sent|wparam, 1 },
1358     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1359     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1360     { WM_MOVE, sent|defwinproc },
1361     { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1362     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1363     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1364     /* FIXME: Wine creates an icon/title window while Windows doesn't */
1365     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1366     { WM_GETTEXT, sent|optional },
1367     { 0 }
1368 };
1369 /* repeated ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1370 static const struct message WmShowChildInvisibleParentSeq_4r[] = {
1371     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1372     { 0 }
1373 };
1374 /* ShowWindow(SW_SHOW) for child with invisible parent */
1375 static const struct message WmShowChildInvisibleParentSeq_5[] = {
1376     { WM_SHOWWINDOW, sent|wparam, 1 },
1377     { 0 }
1378 };
1379 /* ShowWindow(SW_HIDE) for child with invisible parent */
1380 static const struct message WmHideChildInvisibleParentSeq[] = {
1381     { WM_SHOWWINDOW, sent|wparam, 0 },
1382     { 0 }
1383 };
1384 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
1385 static const struct message WmShowChildInvisibleParentSeq_6[] = {
1386     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1387     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1388     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1389     { 0 }
1390 };
1391 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
1392 static const struct message WmHideChildInvisibleParentSeq_2[] = {
1393     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1394     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1395     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1396     { 0 }
1397 };
1398 /* DestroyWindow for a visible child window */
1399 static const struct message WmDestroyChildSeq[] = {
1400     { HCBT_DESTROYWND, hook },
1401     { 0x0090, sent|optional },
1402     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1403     { WM_SHOWWINDOW, sent|wparam, 0 },
1404     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1405     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1406     { WM_ERASEBKGND, sent|parent|optional },
1407     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1408     { HCBT_SETFOCUS, hook }, /* set focus to a parent */
1409     { WM_KILLFOCUS, sent },
1410     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1411     { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
1412     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1413     { WM_SETFOCUS, sent|parent },
1414     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1415     { WM_DESTROY, sent },
1416     { WM_DESTROY, sent|optional }, /* some other (IME?) window */
1417     { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
1418     { WM_NCDESTROY, sent },
1419     { 0 }
1420 };
1421 /* visible child window destroyed by thread exit */
1422 static const struct message WmExitThreadSeq[] = {
1423     { WM_NCDESTROY, sent },  /* actually in grandchild */
1424     { WM_PAINT, sent|parent },
1425     { WM_ERASEBKGND, sent|parent|beginpaint },
1426     { 0 }
1427 };
1428 /* DestroyWindow for a visible child window with invisible parent */
1429 static const struct message WmDestroyInvisibleChildSeq[] = {
1430     { HCBT_DESTROYWND, hook },
1431     { 0x0090, sent|optional },
1432     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1433     { WM_SHOWWINDOW, sent|wparam, 0 },
1434     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1435     { WM_DESTROY, sent },
1436     { WM_NCDESTROY, sent },
1437     { 0 }
1438 };
1439 /* Resizing child window with MoveWindow (32) */
1440 static const struct message WmResizingChildWithMoveWindowSeq[] = {
1441     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
1442     { WM_NCCALCSIZE, sent|wparam, 1 },
1443     { WM_ERASEBKGND, sent|parent|optional },
1444     { WM_ERASEBKGND, sent|optional },
1445     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE },
1446     { WM_MOVE, sent|defwinproc },
1447     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1448     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1449     { 0 }
1450 };
1451 /* Creation of a custom dialog (32) */
1452 static const struct message WmCreateCustomDialogSeq[] = {
1453     { HCBT_CREATEWND, hook },
1454     { WM_GETMINMAXINFO, sent },
1455     { WM_NCCREATE, sent },
1456     { WM_NCCALCSIZE, sent|wparam, 0 },
1457     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1458     { WM_CREATE, sent },
1459     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1460     { WM_NOTIFYFORMAT, sent|optional },
1461     { WM_QUERYUISTATE, sent|optional },
1462     { WM_WINDOWPOSCHANGING, sent|optional },
1463     { WM_GETMINMAXINFO, sent|optional },
1464     { WM_NCCALCSIZE, sent|optional },
1465     { WM_WINDOWPOSCHANGED, sent|optional },
1466     { WM_SHOWWINDOW, sent|wparam, 1 },
1467     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1468     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1469     { HCBT_ACTIVATE, hook },
1470     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1471 
1472 
1473     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1474 
1475     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1476 
1477     { WM_NCACTIVATE, sent },
1478     { WM_GETTEXT, sent|optional|defwinproc },
1479     { WM_GETTEXT, sent|optional|defwinproc },
1480     { WM_GETTEXT, sent|optional|defwinproc },
1481     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
1482     { WM_ACTIVATE, sent|wparam, 1 },
1483     { WM_GETTEXT, sent|optional },
1484     { WM_KILLFOCUS, sent|parent },
1485     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1486     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1487     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1488     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1489     { WM_SETFOCUS, sent },
1490     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1491     { WM_NCPAINT, sent|wparam, 1 },
1492     { WM_GETTEXT, sent|optional|defwinproc },
1493     { WM_GETTEXT, sent|optional|defwinproc },
1494     { WM_ERASEBKGND, sent },
1495     { WM_CTLCOLORDLG, sent|optional|defwinproc },
1496     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1497     { WM_GETTEXT, sent|optional },
1498     { WM_GETTEXT, sent|optional },
1499     { WM_NCCALCSIZE, sent|optional },
1500     { WM_NCPAINT, sent|optional },
1501     { WM_GETTEXT, sent|optional|defwinproc },
1502     { WM_GETTEXT, sent|optional|defwinproc },
1503     { WM_ERASEBKGND, sent|optional },
1504     { WM_CTLCOLORDLG, sent|optional|defwinproc },
1505     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1506     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1507     { WM_MOVE, sent },
1508     { 0 }
1509 };
1510 /* Calling EndDialog for a custom dialog (32) */
1511 static const struct message WmEndCustomDialogSeq[] = {
1512     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1513     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1514     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1515     { WM_GETTEXT, sent|optional },
1516     { HCBT_ACTIVATE, hook },
1517     { WM_NCACTIVATE, sent|wparam, 0 },
1518     { WM_GETTEXT, sent|optional|defwinproc },
1519     { WM_GETTEXT, sent|optional|defwinproc },
1520     { WM_ACTIVATE, sent|wparam, 0 },
1521     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1522     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1523     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1524     { WM_GETTEXT, sent|optional|defwinproc },
1525     { WM_GETTEXT, sent|optional|defwinproc },
1526     { HCBT_SETFOCUS, hook },
1527     { WM_KILLFOCUS, sent },
1528     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1529     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1530     { WM_IME_NOTIFY, sent|wparam|optional, 1 },
1531     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1532     { WM_SETFOCUS, sent|parent|defwinproc },
1533     { 0 }
1534 };
1535 /* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
1536 static const struct message WmShowCustomDialogSeq[] = {
1537     { WM_SHOWWINDOW, sent|wparam, 1 },
1538     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1539     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1540     { HCBT_ACTIVATE, hook },
1541     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1542 
1543     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1544 
1545     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1546     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
1547     { WM_NCACTIVATE, sent },
1548     { WM_ACTIVATE, sent|wparam, 1 },
1549     { WM_GETTEXT, sent|optional },
1550 
1551     { WM_KILLFOCUS, sent|parent },
1552     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1553     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1554     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1555     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1556     { WM_SETFOCUS, sent },
1557     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1558     { WM_NCPAINT, sent|wparam, 1 },
1559     { WM_ERASEBKGND, sent },
1560     { WM_CTLCOLORDLG, sent|defwinproc },
1561     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1562     { 0 }
1563 };
1564 /* Creation and destruction of a modal dialog (32) */
1565 static const struct message WmModalDialogSeq[] = {
1566     { WM_CANCELMODE, sent|parent },
1567     { HCBT_SETFOCUS, hook },
1568     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1569     { WM_KILLFOCUS, sent|parent },
1570     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1571     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1572     { WM_ENABLE, sent|parent|wparam, 0 },
1573     { HCBT_CREATEWND, hook },
1574     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1575     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1576     { WM_SETFONT, sent },
1577     { WM_INITDIALOG, sent },
1578     { WM_CHANGEUISTATE, sent|optional },
1579     { WM_UPDATEUISTATE, sent|optional },
1580     { WM_SHOWWINDOW, sent },
1581     { HCBT_ACTIVATE, hook },
1582     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1583     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1584     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1585     { WM_NCACTIVATE, sent },
1586     { WM_GETTEXT, sent|optional },
1587     { WM_ACTIVATE, sent|wparam, 1 },
1588     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1589     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1590     { WM_NCPAINT, sent|optional },
1591     { WM_GETTEXT, sent|optional },
1592     { WM_ERASEBKGND, sent|optional },
1593     { WM_CTLCOLORDLG, sent|optional },
1594     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1595     { WM_GETTEXT, sent|optional },
1596     { WM_NCCALCSIZE, sent|optional },
1597     { WM_NCPAINT, sent|optional },
1598     { WM_GETTEXT, sent|optional },
1599     { WM_ERASEBKGND, sent|optional },
1600     { WM_CTLCOLORDLG, sent|optional },
1601     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1602     { WM_PAINT, sent|optional },
1603     { WM_CTLCOLORBTN, sent|optional },
1604     { WM_GETTITLEBARINFOEX, sent|optional },
1605     { WM_ENTERIDLE, sent|parent|optional },
1606     { WM_ENTERIDLE, sent|parent|optional },
1607     { WM_ENTERIDLE, sent|parent|optional },
1608     { WM_ENTERIDLE, sent|parent|optional },
1609     { WM_ENTERIDLE, sent|parent|optional },
1610     { WM_ENTERIDLE, sent|parent|optional },
1611     { WM_ENTERIDLE, sent|parent|optional },
1612     { WM_ENTERIDLE, sent|parent|optional },
1613     { WM_ENTERIDLE, sent|parent|optional },
1614     { WM_ENTERIDLE, sent|parent|optional },
1615     { WM_ENTERIDLE, sent|parent|optional },
1616     { WM_ENTERIDLE, sent|parent|optional },
1617     { WM_ENTERIDLE, sent|parent|optional },
1618     { WM_ENTERIDLE, sent|parent|optional },
1619     { WM_ENTERIDLE, sent|parent|optional },
1620     { WM_ENTERIDLE, sent|parent|optional },
1621     { WM_ENTERIDLE, sent|parent|optional },
1622     { WM_ENTERIDLE, sent|parent|optional },
1623     { WM_ENTERIDLE, sent|parent|optional },
1624     { WM_ENTERIDLE, sent|parent|optional },
1625     { WM_TIMER, sent },
1626     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1627     { WM_ENABLE, sent|parent|wparam, 1 },
1628     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1629     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1630     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1631     { WM_GETTEXT, sent|optional },
1632     { HCBT_ACTIVATE, hook },
1633     { WM_NCACTIVATE, sent|wparam, 0 },
1634     { WM_GETTEXT, sent|optional },
1635     { WM_ACTIVATE, sent|wparam, 0 },
1636     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1637     { WM_WINDOWPOSCHANGING, sent|optional },
1638     { WM_WINDOWPOSCHANGED, sent|optional },
1639     { HCBT_SETFOCUS, hook },
1640     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1641     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1642     { WM_SETFOCUS, sent|parent|defwinproc },
1643     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 },
1644     { HCBT_DESTROYWND, hook },
1645     { 0x0090, sent|optional },
1646     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1647     { WM_DESTROY, sent },
1648     { WM_NCDESTROY, sent },
1649     { 0 }
1650 };
1651 static const struct message WmModalDialogSeq_2[] = {
1652     { WM_CANCELMODE, sent },
1653     { HCBT_SETFOCUS, hook },
1654     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1655     { WM_KILLFOCUS, sent },
1656     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1657     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1658     { WM_ENABLE, sent|wparam, 0 },
1659     { HCBT_CREATEWND, hook },
1660     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1661     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1662     { WM_SETFONT, sent },
1663     { WM_INITDIALOG, sent },
1664     { WM_CHANGEUISTATE, sent|optional },
1665     { WM_UPDATEUISTATE, sent|optional },
1666     { WM_ENABLE, sent|wparam, 1 },
1667     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1668     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1669     { WM_CHANGEUISTATE, sent|optional },
1670     { WM_UPDATEUISTATE, sent|optional },
1671     { HCBT_DESTROYWND, hook },
1672     { 0x0090, sent|optional },
1673     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1674     { WM_DESTROY, sent },
1675     { WM_NCDESTROY, sent },
1676     { 0 }
1677 };
1678 /* SetMenu for NonVisible windows with size change*/
1679 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
1680     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1681     { WM_NCCALCSIZE, sent|wparam, 1 },
1682     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1683     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
1684     { WM_MOVE, sent|defwinproc },
1685     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1686     { WM_NCCALCSIZE,sent|wparam|optional, 1 }, /* XP */
1687     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1688     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1689     { WM_GETTEXT, sent|optional },
1690     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1691     { 0 }
1692 };
1693 /* SetMenu for NonVisible windows with no size change */
1694 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
1695     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1696     { WM_NCCALCSIZE, sent|wparam, 1 },
1697     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1698     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1699     { 0 }
1700 };
1701 /* SetMenu for Visible windows with size change */
1702 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
1703     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1704     { WM_NCCALCSIZE, sent|wparam, 1 },
1705     { 0x0093, sent|defwinproc|optional },
1706     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1707     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1708     { 0x0093, sent|defwinproc|optional },
1709     { 0x0093, sent|defwinproc|optional },
1710     { 0x0091, sent|defwinproc|optional },
1711     { 0x0092, sent|defwinproc|optional },
1712     { WM_GETTEXT, sent|defwinproc|optional },
1713     { WM_ERASEBKGND, sent|optional },
1714     { WM_ACTIVATE, sent|optional },
1715     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1716     { WM_MOVE, sent|defwinproc },
1717     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1718     { 0x0093, sent|optional },
1719     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1720     { 0x0093, sent|defwinproc|optional },
1721     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1722     { 0x0093, sent|defwinproc|optional },
1723     { 0x0093, sent|defwinproc|optional },
1724     { 0x0091, sent|defwinproc|optional },
1725     { 0x0092, sent|defwinproc|optional },
1726     { WM_ERASEBKGND, sent|optional },
1727     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1728     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1729     { 0 }
1730 };
1731 /* SetMenu for Visible windows with no size change */
1732 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
1733     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1734     { WM_NCCALCSIZE, sent|wparam, 1 },
1735     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1736     { WM_GETTEXT, sent|defwinproc|optional },
1737     { WM_ERASEBKGND, sent|optional },
1738     { WM_ACTIVATE, sent|optional },
1739     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1740     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1741     { 0 }
1742 };
1743 /* DrawMenuBar for a visible window */
1744 static const struct message WmDrawMenuBarSeq[] =
1745 {
1746     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1747     { WM_NCCALCSIZE, sent|wparam, 1 },
1748     { 0x0093, sent|defwinproc|optional },
1749     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1750     { 0x0093, sent|defwinproc|optional },
1751     { 0x0093, sent|defwinproc|optional },
1752     { 0x0091, sent|defwinproc|optional },
1753     { 0x0092, sent|defwinproc|optional },
1754     { WM_GETTEXT, sent|defwinproc|optional },
1755     { WM_ERASEBKGND, sent|optional },
1756     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1757     { 0x0093, sent|optional },
1758     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1759     { 0 }
1760 };
1761 
1762 static const struct message WmSetRedrawFalseSeq[] =
1763 {
1764     { WM_SETREDRAW, sent|wparam, 0 },
1765     { 0 }
1766 };
1767 
1768 static const struct message WmSetRedrawTrueSeq[] =
1769 {
1770     { WM_SETREDRAW, sent|wparam, 1 },
1771     { 0 }
1772 };
1773 
1774 static const struct message WmEnableWindowSeq_1[] =
1775 {
1776     { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1777     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1778     { HCBT_SETFOCUS, hook|optional },
1779     { WM_KILLFOCUS, sent|optional },
1780     { WM_ENABLE, sent|wparam|lparam, FALSE, 0 },
1781     { 0 }
1782 };
1783 
1784 static const struct message WmEnableWindowSeq_2[] =
1785 {
1786     { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1787     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1788     { 0 }
1789 };
1790 
1791 static const struct message WmEnableWindowSeq_3[] =
1792 {
1793     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1794     { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
1795     { 0 }
1796 };
1797 
1798 static const struct message WmEnableWindowSeq_4[] =
1799 {
1800     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1801     { 0 }
1802 };
1803 
1804 static const struct message WmGetScrollRangeSeq[] =
1805 {
1806     { SBM_GETRANGE, sent },
1807     { 0 }
1808 };
1809 static const struct message WmGetScrollInfoSeq[] =
1810 {
1811     { SBM_GETSCROLLINFO, sent },
1812     { 0 }
1813 };
1814 static const struct message WmSetScrollRangeSeq[] =
1815 {
1816     /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
1817        sends SBM_SETSCROLLINFO.
1818      */
1819     { SBM_SETSCROLLINFO, sent },
1820     { 0 }
1821 };
1822 /* SetScrollRange for a window without a non-client area */
1823 static const struct message WmSetScrollRangeHSeq_empty[] =
1824 {
1825     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_HSCROLL, 0 },
1826     { 0 }
1827 };
1828 static const struct message WmSetScrollRangeVSeq_empty[] =
1829 {
1830     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_VSCROLL, 0 },
1831     { 0 }
1832 };
1833 static const struct message WmSetScrollRangeHVSeq[] =
1834 {
1835     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1836     { WM_NCCALCSIZE, sent|wparam, 1 },
1837     { WM_GETTEXT, sent|defwinproc|optional },
1838     { WM_ERASEBKGND, sent|optional },
1839     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1840     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1841     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1842     { 0 }
1843 };
1844 /* SetScrollRange for a window with a non-client area */
1845 static const struct message WmSetScrollRangeHV_NC_Seq[] =
1846 {
1847     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1848     { WM_NCCALCSIZE, sent|wparam, 1 },
1849     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1850     { WM_NCPAINT, sent|optional },
1851     { WM_STYLECHANGING, sent|defwinproc|optional },
1852     { WM_STYLECHANGED, sent|defwinproc|optional },
1853     { WM_STYLECHANGING, sent|defwinproc|optional },
1854     { WM_STYLECHANGED, sent|defwinproc|optional },
1855     { WM_STYLECHANGING, sent|defwinproc|optional },
1856     { WM_STYLECHANGED, sent|defwinproc|optional },
1857     { WM_STYLECHANGING, sent|defwinproc|optional },
1858     { WM_STYLECHANGED, sent|defwinproc|optional },
1859     { WM_GETTEXT, sent|defwinproc|optional },
1860     { WM_GETTEXT, sent|defwinproc|optional },
1861     { WM_ERASEBKGND, sent|optional },
1862     { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
1863     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOCLIENTSIZE },
1864     { WM_SIZE, sent|defwinproc|optional },
1865     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1866     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1867     { WM_GETTEXT, sent|optional },
1868     { WM_GETTEXT, sent|optional },
1869     { WM_GETTEXT, sent|optional },
1870     { WM_GETTEXT, sent|optional },
1871     { 0 }
1872 };
1873 /* test if we receive the right sequence of messages */
1874 /* after calling ShowWindow( SW_SHOWNA) */
1875 static const struct message WmSHOWNAChildInvisParInvis[] = {
1876     { WM_SHOWWINDOW, sent|wparam, 1 },
1877     { 0 }
1878 };
1879 static const struct message WmSHOWNAChildVisParInvis[] = {
1880     { WM_SHOWWINDOW, sent|wparam, 1 },
1881     { 0 }
1882 };
1883 static const struct message WmSHOWNAChildVisParVis[] = {
1884     { WM_SHOWWINDOW, sent|wparam, 1 },
1885     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1886     { 0 }
1887 };
1888 static const struct message WmSHOWNAChildInvisParVis[] = {
1889     { WM_SHOWWINDOW, sent|wparam, 1 },
1890     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1891     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1892     { WM_ERASEBKGND, sent|optional },
1893     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOCLIENTMOVE },
1894     { 0 }
1895 };
1896 static const struct message WmSHOWNATopVisible[] = {
1897     { WM_SHOWWINDOW, sent|wparam, 1 },
1898     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1899     { WM_NCPAINT, sent|wparam|optional, 1 },
1900     { WM_GETTEXT, sent|defwinproc|optional },
1901     { WM_ERASEBKGND, sent|optional },
1902     { WM_WINDOWPOSCHANGED, sent|optional },
1903     { 0 }
1904 };
1905 static const struct message WmSHOWNATopInvisible[] = {
1906     { WM_NOTIFYFORMAT, sent|optional },
1907     { WM_QUERYUISTATE, sent|optional },
1908     { WM_WINDOWPOSCHANGING, sent|optional },
1909     { WM_GETMINMAXINFO, sent|optional },
1910     { WM_NCCALCSIZE, sent|optional },
1911     { WM_WINDOWPOSCHANGED, sent|optional },
1912     { WM_SHOWWINDOW, sent|wparam, 1 },
1913     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1914     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1915     { WM_NCPAINT, sent|wparam|optional, 1 },
1916     { WM_GETTEXT, sent|defwinproc|optional },
1917     { WM_ERASEBKGND, sent|optional },
1918     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1919     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1920     { WM_NCPAINT, sent|wparam|optional, 1 },
1921     { WM_ERASEBKGND, sent|optional },
1922     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1923     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1924     { WM_MOVE, sent },
1925     { 0 }
1926 };
1927 
1928 static const struct message WmTrackPopupMenu[] = {
1929     { HCBT_CREATEWND, hook },
1930     { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1931     { WM_INITMENU, sent|lparam, 0, 0 },
1932     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1933     { 0x0093, sent|optional },
1934     { 0x0094, sent|optional },
1935     { 0x0094, sent|optional },
1936     { WM_ENTERIDLE, sent|wparam, 2 },
1937     { WM_CAPTURECHANGED, sent },
1938     { HCBT_DESTROYWND, hook },
1939     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1940     { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
1941     { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1942     { 0 }
1943 };
1944 
1945 static const struct message WmTrackPopupMenuEsc[] = {
1946     { 0 }
1947 };
1948 
1949 static const struct message WmTrackPopupMenuCapture[] = {
1950     { HCBT_CREATEWND, hook },
1951     { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1952     { WM_CAPTURECHANGED, sent },
1953     { WM_INITMENU, sent|lparam, 0, 0 },
1954     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1955     { 0x0093, sent|optional },
1956     { 0x0094, sent|optional },
1957     { 0x0094, sent|optional },
1958     { WM_ENTERIDLE, sent|wparam, 2 },
1959     { WM_CAPTURECHANGED, sent },
1960     { HCBT_DESTROYWND, hook },
1961     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1962     { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
1963     { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1964     { 0 }
1965 };
1966 
1967 static const struct message WmTrackPopupMenuEmpty[] = {
1968     { HCBT_CREATEWND, hook },
1969     { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1970     { WM_INITMENU, sent|lparam, 0, 0 },
1971     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1972     { 0x0093, sent|optional },
1973     { 0x0094, sent|optional },
1974     { 0x0094, sent|optional },
1975     { WM_CAPTURECHANGED, sent },
1976     { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1977     { HCBT_DESTROYWND, hook },
1978     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1979     { 0 }
1980 };
1981 
1982 static const struct message WmTrackPopupMenuAbort[] = {
1983     { HCBT_CREATEWND, hook },
1984     { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1985     { WM_INITMENU, sent|lparam, 0, 0 },
1986     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1987     { 0x0093, sent|optional },
1988     { 0x0094, sent|optional },
1989     { 0x0094, sent|optional },
1990     { WM_CAPTURECHANGED, sent },
1991     { HCBT_DESTROYWND, hook },
1992     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1993     { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
1994     { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1995     { 0 }
1996 };
1997 
1998 static BOOL after_end_dialog, test_def_id, paint_loop_done;
1999 static int sequence_cnt, sequence_size;
2000 static struct recvd_message* sequence;
2001 static int log_all_parent_messages;
2002 static CRITICAL_SECTION sequence_cs;
2003 
2004 /* user32 functions */
2005 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
2006 static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO);
2007 static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG);
2008 static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO);
2009 static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD);
2010 static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*);
2011 static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
2012 static BOOL (WINAPI *pGetMonitorInfoA)(HMONITOR,LPMONITORINFO);
2013 static HMONITOR (WINAPI *pMonitorFromPoint)(POINT,DWORD);
2014 static BOOL (WINAPI *pUpdateLayeredWindow)(HWND,HDC,POINT*,SIZE*,HDC,POINT*,COLORREF,BLENDFUNCTION*,DWORD);
2015 static UINT_PTR (WINAPI *pSetSystemTimer)(HWND, UINT_PTR, UINT, TIMERPROC);
2016 static UINT_PTR (WINAPI *pKillSystemTimer)(HWND, UINT_PTR);
2017 static UINT_PTR (WINAPI *pSetCoalescableTimer)(HWND, UINT_PTR, UINT, TIMERPROC, ULONG);
2018 /* kernel32 functions */
2019 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
2020 
2021 static void init_procs(void)
2022 {
2023     HMODULE user32 = GetModuleHandleA("user32.dll");
2024     HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
2025 
2026 #define GET_PROC(dll, func) \
2027     p ## func = (void*)GetProcAddress(dll, #func); \
2028     if(!p ## func) { \
2029       trace("GetProcAddress(%s) failed\n", #func); \
2030     }
2031 
2032     GET_PROC(user32, GetAncestor)
2033     GET_PROC(user32, GetMenuInfo)
2034     GET_PROC(user32, NotifyWinEvent)
2035     GET_PROC(user32, SetMenuInfo)
2036     GET_PROC(user32, SetWinEventHook)
2037     GET_PROC(user32, TrackMouseEvent)
2038     GET_PROC(user32, UnhookWinEvent)
2039     GET_PROC(user32, GetMonitorInfoA)
2040     GET_PROC(user32, MonitorFromPoint)
2041     GET_PROC(user32, UpdateLayeredWindow)
2042     GET_PROC(user32, SetSystemTimer)
2043     GET_PROC(user32, KillSystemTimer)
2044     GET_PROC(user32, SetCoalescableTimer)
2045 
2046     GET_PROC(kernel32, GetCPInfoExA)
2047 
2048 #undef GET_PROC
2049 }
2050 
2051 static const char *get_winpos_flags(UINT flags)
2052 {
2053     static char buffer[300];
2054 
2055     buffer[0] = 0;
2056 #define DUMP(flag) do { if (flags & flag) { strcat( buffer, "|" #flag ); flags &= ~flag; } } while(0)
2057     DUMP( SWP_SHOWWINDOW );
2058     DUMP( SWP_HIDEWINDOW );
2059     DUMP( SWP_NOACTIVATE );
2060     DUMP( SWP_FRAMECHANGED );
2061     DUMP( SWP_NOCOPYBITS );
2062     DUMP( SWP_NOOWNERZORDER );
2063     DUMP( SWP_NOSENDCHANGING );
2064     DUMP( SWP_DEFERERASE );
2065     DUMP( SWP_ASYNCWINDOWPOS );
2066     DUMP( SWP_NOZORDER );
2067     DUMP( SWP_NOREDRAW );
2068     DUMP( SWP_NOSIZE );
2069     DUMP( SWP_NOMOVE );
2070     DUMP( SWP_NOCLIENTSIZE );
2071     DUMP( SWP_NOCLIENTMOVE );
2072     if (flags) sprintf(buffer + strlen(buffer),"|0x%04x", flags);
2073     return buffer + 1;
2074 #undef DUMP
2075 }
2076 
2077 static BOOL ignore_message( UINT message )
2078 {
2079     /* these are always ignored */
2080     return (message >= 0xc000 ||
2081             message == WM_GETICON ||
2082             message == WM_GETOBJECT ||
2083             message == WM_TIMECHANGE ||
2084             message == WM_DISPLAYCHANGE ||
2085             message == WM_DEVICECHANGE ||
2086             message == WM_DWMNCRENDERINGCHANGED);
2087 }
2088 
2089 static unsigned hash_Ly_W(const WCHAR *str)
2090 {
2091     unsigned hash = 0;
2092 
2093     for (; *str; str++)
2094         hash = hash * 1664525u + (unsigned char)(*str) + 1013904223u;
2095 
2096     return hash;
2097 }
2098 
2099 static unsigned hash_Ly(const char *str)
2100 {
2101     unsigned hash = 0;
2102 
2103     for (; *str; str++)
2104         hash = hash * 1664525u + (unsigned char)(*str) + 1013904223u;
2105 
2106     return hash;
2107 }
2108 
2109 #define add_message(msg) add_message_(__LINE__,msg);
2110 static void add_message_(int line, const struct recvd_message *msg)
2111 {
2112     struct recvd_message *seq;
2113 
2114     EnterCriticalSection( &sequence_cs );
2115     if (!sequence)
2116     {
2117 	sequence_size = 10;
2118 	sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof(*sequence) );
2119     }
2120     if (sequence_cnt == sequence_size)
2121     {
2122 	sequence_size *= 2;
2123 	sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof(*sequence) );
2124     }
2125     assert(sequence);
2126 
2127     seq = &sequence[sequence_cnt++];
2128     seq->hwnd = msg->hwnd;
2129     seq->message = msg->message;
2130     seq->flags = msg->flags;
2131     seq->wParam = msg->wParam;
2132     seq->lParam = msg->lParam;
2133     seq->line   = line;
2134     seq->descr  = msg->descr;
2135     seq->output[0] = 0;
2136     LeaveCriticalSection( &sequence_cs );
2137 
2138     if (msg->descr)
2139     {
2140         if (msg->flags & hook)
2141         {
2142             static const char * const CBT_code_name[10] =
2143             {
2144                 "HCBT_MOVESIZE",
2145                 "HCBT_MINMAX",
2146                 "HCBT_QS",
2147                 "HCBT_CREATEWND",
2148                 "HCBT_DESTROYWND",
2149                 "HCBT_ACTIVATE",
2150                 "HCBT_CLICKSKIPPED",
2151                 "HCBT_KEYSKIPPED",
2152                 "HCBT_SYSCOMMAND",
2153                 "HCBT_SETFOCUS"
2154             };
2155             const char *code_name = (msg->message <= HCBT_SETFOCUS) ? CBT_code_name[msg->message] : "Unknown";
2156 
2157             sprintf( seq->output, "%s: hook %d (%s) wp %08lx lp %08lx",
2158                      msg->descr, msg->message, code_name, msg->wParam, msg->lParam );
2159         }
2160         else if (msg->flags & winevent_hook)
2161         {
2162             sprintf( seq->output, "%s: winevent %p %08x %08lx %08lx",
2163                      msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
2164         }
2165         else
2166         {
2167             switch (msg->message)
2168             {
2169             case WM_WINDOWPOSCHANGING:
2170             case WM_WINDOWPOSCHANGED:
2171             {
2172                 WINDOWPOS *winpos = (WINDOWPOS *)msg->lParam;
2173 
2174                 sprintf( seq->output, "%s: %p WM_WINDOWPOS%s wp %08lx lp %08lx after %p x %d y %d cx %d cy %d flags %s",
2175                           msg->descr, msg->hwnd,
2176                           (msg->message == WM_WINDOWPOSCHANGING) ? "CHANGING" : "CHANGED",
2177                           msg->wParam, msg->lParam, winpos->hwndInsertAfter,
2178                           winpos->x, winpos->y, winpos->cx, winpos->cy,
2179                           get_winpos_flags(winpos->flags) );
2180 
2181                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2182                  * in the high word for internal purposes
2183                  */
2184                 seq->wParam = winpos->flags & 0xffff;
2185                 /* We are not interested in the flags that don't match under XP and Win9x */
2186                 seq->wParam &= ~SWP_NOZORDER;
2187                 break;
2188             }
2189 
2190             case WM_DRAWITEM:
2191             {
2192                 DRAW_ITEM_STRUCT di;
2193                 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)msg->lParam;
2194 
2195                 sprintf( seq->output, "%s: %p WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x",
2196                          msg->descr, msg->hwnd, dis->CtlType, dis->CtlID,
2197                          dis->itemID, dis->itemAction, dis->itemState);
2198 
2199                 di.u.lp = 0;
2200                 di.u.item.type = dis->CtlType;
2201                 di.u.item.ctl_id = dis->CtlID;
2202                 if (dis->CtlType == ODT_LISTBOX ||
2203                     dis->CtlType == ODT_COMBOBOX ||
2204                     dis->CtlType == ODT_MENU)
2205                     di.u.item.item_id = dis->itemID;
2206                 di.u.item.action = dis->itemAction;
2207                 di.u.item.state = dis->itemState;
2208 
2209                 seq->lParam = di.u.lp;
2210                 break;
2211             }
2212 
2213             case WM_MEASUREITEM:
2214             {
2215                 MEASURE_ITEM_STRUCT mi;
2216                 MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *)msg->lParam;
2217                 BOOL is_unicode_data = TRUE;
2218 
2219                 sprintf( seq->output, "%s: %p WM_MEASUREITEM: CtlType %#x, CtlID %#x, itemID %#x, itemData %#lx",
2220                          msg->descr, msg->hwnd, mis->CtlType, mis->CtlID,
2221                          mis->itemID, mis->itemData);
2222 
2223                 if (mis->CtlType == ODT_LISTBOX)
2224                 {
2225                     HWND ctrl = GetDlgItem(msg->hwnd, mis->CtlID);
2226                     is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS;
2227                 }
2228 
2229                 mi.u.wp = 0;
2230                 mi.u.item.CtlType = mis->CtlType;
2231                 mi.u.item.CtlID = mis->CtlID;
2232                 mi.u.item.itemID = mis->itemID;
2233                 mi.u.item.wParam = msg->wParam;
2234                 seq->wParam = mi.u.wp;
2235                 if (is_unicode_data)
2236                     seq->lParam = mis->itemData ? hash_Ly_W((const WCHAR *)mis->itemData) : 0;
2237                 else
2238                     seq->lParam = mis->itemData ? hash_Ly((const char *)mis->itemData) : 0;
2239                 break;
2240             }
2241 
2242             case WM_COMPAREITEM:
2243             {
2244                 COMPAREITEMSTRUCT *cis = (COMPAREITEMSTRUCT *)msg->lParam;
2245                 HWND ctrl = GetDlgItem(msg->hwnd, cis->CtlID);
2246                 BOOL is_unicode_data = TRUE;
2247 
2248                 ok(msg->wParam == cis->CtlID, "expected %#x, got %#lx\n", cis->CtlID, msg->wParam);
2249                 ok(cis->hwndItem == ctrl, "expected %p, got %p\n", ctrl, cis->hwndItem);
2250                 ok((int)cis->itemID1 >= 0, "expected >= 0, got %d\n", cis->itemID1);
2251                 ok((int)cis->itemID2 == -1, "expected -1, got %d\n", cis->itemID2);
2252 
2253                 sprintf( seq->output, "%s: %p WM_COMPAREITEM: CtlType %#x, CtlID %#x, itemID1 %#x, itemData1 %#lx, itemID2 %#x, itemData2 %#lx",
2254                          msg->descr, msg->hwnd, cis->CtlType, cis->CtlID,
2255                          cis->itemID1, cis->itemData1, cis->itemID2, cis->itemData2);
2256 
2257                 if (cis->CtlType == ODT_LISTBOX)
2258                     is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS;
2259 
2260                 if (is_unicode_data)
2261                 {
2262                     seq->wParam = cis->itemData1 ? hash_Ly_W((const WCHAR *)cis->itemData1) : 0;
2263                     seq->lParam = cis->itemData2 ? hash_Ly_W((const WCHAR *)cis->itemData2) : 0;
2264                 }
2265                 else
2266                 {
2267                     seq->wParam = cis->itemData1 ? hash_Ly((const char *)cis->itemData1) : 0;
2268                     seq->lParam = cis->itemData2 ? hash_Ly((const char *)cis->itemData2) : 0;
2269                 }
2270                 break;
2271             }
2272 
2273             default:
2274                 if (msg->message >= 0xc000) return;  /* ignore registered messages */
2275                 sprintf( seq->output, "%s: %p %04x wp %08lx lp %08lx",
2276                          msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
2277             }
2278             if (msg->flags & (sent|posted|parent|defwinproc|beginpaint))
2279                 sprintf( seq->output + strlen(seq->output), " (flags %x)", msg->flags );
2280         }
2281     }
2282 }
2283 
2284 /* try to make sure pending X events have been processed before continuing */
2285 static void flush_events(void)
2286 {
2287     MSG msg;
2288     int diff = 200;
2289     int min_timeout = 100;
2290     DWORD time = GetTickCount() + diff;
2291 
2292     while (diff > 0)
2293     {
2294         if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
2295         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
2296         diff = time - GetTickCount();
2297     }
2298 }
2299 
2300 static void flush_sequence(void)
2301 {
2302     EnterCriticalSection( &sequence_cs );
2303     HeapFree(GetProcessHeap(), 0, sequence);
2304     sequence = 0;
2305     sequence_cnt = sequence_size = 0;
2306     LeaveCriticalSection( &sequence_cs );
2307 }
2308 
2309 static void dump_sequence(const struct message *expected, const char *context, const char *file, int line)
2310 {
2311     const struct recvd_message *actual = sequence;
2312     unsigned int count = 0;
2313 
2314     trace_(file, line)("Failed sequence %s:\n", context );
2315     while (expected->message && actual->message)
2316     {
2317         if (actual->output[0])
2318         {
2319             if (expected->flags & hook)
2320             {
2321                 trace_(file, line)( "  %u: expected: hook %04x - actual: %s\n",
2322                                     count, expected->message, actual->output );
2323             }
2324             else if (expected->flags & winevent_hook)
2325             {
2326                 trace_(file, line)( "  %u: expected: winevent %04x - actual: %s\n",
2327                                     count, expected->message, actual->output );
2328             }
2329             else if (expected->flags & kbd_hook)
2330             {
2331                 trace_(file, line)( "  %u: expected: kbd %04x - actual: %s\n",
2332                                     count, expected->message, actual->output );
2333             }
2334             else
2335             {
2336                 trace_(file, line)( "  %u: expected: msg %04x - actual: %s\n",
2337                                     count, expected->message, actual->output );
2338             }
2339         }
2340 
2341 	if (expected->message == actual->message)
2342 	{
2343 	    if ((expected->flags & defwinproc) != (actual->flags & defwinproc) &&
2344                 (expected->flags & optional))
2345             {
2346                 /* don't match messages if their defwinproc status differs */
2347                 expected++;
2348             }
2349             else
2350             {
2351                 expected++;
2352                 actual++;
2353             }
2354 	}
2355 	/* silently drop winevent messages if there is no support for them */
2356 	else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
2357 	    expected++;
2358         else
2359         {
2360             expected++;
2361             actual++;
2362         }
2363         count++;
2364     }
2365 
2366     /* optional trailing messages */
2367     while (expected->message && ((expected->flags & optional) ||
2368 	    ((expected->flags & winevent_hook) && !hEvent_hook)))
2369     {
2370         trace_(file, line)( "  %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2371 	expected++;
2372         count++;
2373     }
2374 
2375     if (expected->message)
2376     {
2377         trace_(file, line)( "  %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2378         return;
2379     }
2380 
2381     while (actual->message && actual->output[0])
2382     {
2383         trace_(file, line)( "  %u: expected: nothing - actual: %s\n", count, actual->output );
2384         actual++;
2385         count++;
2386     }
2387 }
2388 
2389 #define ok_sequence( exp, contx, todo) \
2390         ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
2391 
2392 
2393 static void ok_sequence_(const struct message *expected_list, const char *context, BOOL todo,
2394                          const char *file, int line)
2395 {
2396     static const struct recvd_message end_of_sequence;
2397     const struct message *expected = expected_list;
2398     const struct recvd_message *actual;
2399     int failcount = 0, dump = 0;
2400     unsigned int count = 0;
2401 
2402     add_message(&end_of_sequence);
2403 
2404     actual = sequence;
2405 
2406     while (expected->message && actual->message)
2407     {
2408 	if (expected->message == actual->message &&
2409             !((expected->flags ^ actual->flags) & (hook|winevent_hook|kbd_hook)))
2410 	{
2411 	    if (expected->flags & wparam)
2412 	    {
2413 		if (((expected->wParam ^ actual->wParam) & ~expected->wp_mask) && todo)
2414 		{
2415 		    todo_wine {
2416                         failcount ++;
2417                         if (strcmp(winetest_platform, "wine")) dump++;
2418                         ok_( file, line) (FALSE,
2419 			    "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2420                             context, count, expected->message, expected->wParam, actual->wParam);
2421 		    }
2422 		}
2423 		else
2424                 {
2425                     ok_( file, line)( ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) == 0,
2426                                      "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2427                                      context, count, expected->message, expected->wParam, actual->wParam);
2428                     if ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) dump++;
2429                 }
2430 
2431 	    }
2432 	    if (expected->flags & lparam)
2433             {
2434 		if (((expected->lParam ^ actual->lParam) & ~expected->lp_mask) && todo)
2435 		{
2436 		    todo_wine {
2437                         failcount ++;
2438                         if (strcmp(winetest_platform, "wine")) dump++;
2439                         ok_( file, line) (FALSE,
2440 			    "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2441                             context, count, expected->message, expected->lParam, actual->lParam);
2442 		    }
2443 		}
2444 		else
2445                 {
2446                     ok_( file, line)(((expected->lParam ^ actual->lParam) & ~expected->lp_mask) == 0,
2447                                      "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2448                                      context, count, expected->message, expected->lParam, actual->lParam);
2449                     if ((expected->lParam ^ actual->lParam) & ~expected->lp_mask) dump++;
2450                 }
2451             }
2452 	    if ((expected->flags & optional) &&
2453                 ((expected->flags ^ actual->flags) & (defwinproc|parent)))
2454             {
2455                 /* don't match optional messages if their defwinproc or parent status differs */
2456                 expected++;
2457                 count++;
2458                 continue;
2459             }
2460 	    if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
2461 	    {
2462 		    todo_wine {
2463                         failcount ++;
2464                         if (strcmp(winetest_platform, "wine")) dump++;
2465                         ok_( file, line) (FALSE,
2466                             "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2467                             context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2468 		    }
2469 	    }
2470 	    else
2471             {
2472 	        ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
2473 		    "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2474                     context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2475                 if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) dump++;
2476             }
2477 
2478 	    ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
2479 		"%s: %u: the msg 0x%04x should %shave been sent by BeginPaint\n",
2480                 context, count, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
2481             if ((expected->flags & beginpaint) != (actual->flags & beginpaint)) dump++;
2482 
2483 	    ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
2484 		"%s: %u: the msg 0x%04x should have been %s\n",
2485                 context, count, expected->message, (expected->flags & posted) ? "posted" : "sent");
2486             if ((expected->flags & (sent|posted)) != (actual->flags & (sent|posted))) dump++;
2487 
2488 	    ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
2489 		"%s: %u: the msg 0x%04x was expected in %s\n",
2490                 context, count, expected->message, (expected->flags & parent) ? "parent" : "child");
2491             if ((expected->flags & parent) != (actual->flags & parent)) dump++;
2492 
2493 	    ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
2494 		"%s: %u: the msg 0x%04x should have been sent by a hook\n",
2495                 context, count, expected->message);
2496             if ((expected->flags & hook) != (actual->flags & hook)) dump++;
2497 
2498 	    ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
2499 		"%s: %u: the msg 0x%04x should have been sent by a winevent hook\n",
2500                 context, count, expected->message);
2501             if ((expected->flags & winevent_hook) != (actual->flags & winevent_hook)) dump++;
2502 
2503 	    ok_( file, line) ((expected->flags & kbd_hook) == (actual->flags & kbd_hook),
2504 		"%s: %u: the msg 0x%04x should have been sent by a keyboard hook\n",
2505                 context, count, expected->message);
2506             if ((expected->flags & kbd_hook) != (actual->flags & kbd_hook)) dump++;
2507 
2508 	    expected++;
2509 	    actual++;
2510 	}
2511 	/* silently drop hook messages if there is no support for them */
2512 	else if ((expected->flags & optional) ||
2513                  ((expected->flags & hook) && !hCBT_hook) ||
2514                  ((expected->flags & winevent_hook) && !hEvent_hook) ||
2515                  ((expected->flags & kbd_hook) && !hKBD_hook))
2516 	    expected++;
2517 	else if (todo)
2518 	{
2519             failcount++;
2520             todo_wine {
2521                 if (strcmp(winetest_platform, "wine")) dump++;
2522                 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2523                                   context, count, expected->message, actual->message);
2524             }
2525             goto done;
2526         }
2527         else
2528         {
2529             ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2530                               context, count, expected->message, actual->message);
2531             dump++;
2532             expected++;
2533             actual++;
2534         }
2535         count++;
2536     }
2537 
2538     /* skip all optional trailing messages */
2539     while (expected->message && ((expected->flags & optional) ||
2540                                  ((expected->flags & hook) && !hCBT_hook) ||
2541                                  ((expected->flags & winevent_hook) && !hEvent_hook)))
2542 	expected++;
2543 
2544     if (todo)
2545     {
2546         todo_wine {
2547             if (expected->message || actual->message) {
2548                 failcount++;
2549                 if (strcmp(winetest_platform, "wine")) dump++;
2550                 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2551                                   context, count, expected->message, actual->message);
2552             }
2553         }
2554     }
2555     else
2556     {
2557         if (expected->message || actual->message)
2558         {
2559             dump++;
2560             ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2561                               context, count, expected->message, actual->message);
2562         }
2563     }
2564     if( todo && !failcount) /* succeeded yet marked todo */
2565         todo_wine {
2566             if (!strcmp(winetest_platform, "wine")) dump++;
2567             ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
2568         }
2569 
2570 done:
2571     if (dump) dump_sequence(expected_list, context, file, line);
2572     flush_sequence();
2573 }
2574 
2575 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT))
2576 
2577 /******************************** MDI test **********************************/
2578 
2579 /* CreateWindow for MDI frame window, initially visible */
2580 static const struct message WmCreateMDIframeSeq[] = {
2581     { HCBT_CREATEWND, hook },
2582     { WM_GETMINMAXINFO, sent },
2583     { WM_NCCREATE, sent },
2584     { WM_NCCALCSIZE, sent|wparam, 0 },
2585     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2586     { WM_CREATE, sent },
2587     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2588     { WM_NOTIFYFORMAT, sent|optional },
2589     { WM_QUERYUISTATE, sent|optional },
2590     { WM_WINDOWPOSCHANGING, sent|optional },
2591     { WM_GETMINMAXINFO, sent|optional },
2592     { WM_NCCALCSIZE, sent|optional },
2593     { WM_WINDOWPOSCHANGED, sent|optional },
2594     { WM_SHOWWINDOW, sent|wparam, 1 },
2595     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2596     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2597     { HCBT_ACTIVATE, hook },
2598     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
2599     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
2600     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
2601     { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
2602     { WM_NCACTIVATE, sent },
2603     { WM_GETTEXT, sent|defwinproc|optional },
2604     { WM_ACTIVATE, sent|wparam, 1 },
2605     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
2606     { HCBT_SETFOCUS, hook },
2607     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2608     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2609     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2610     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
2611     /* Win9x adds SWP_NOZORDER below */
2612     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2613     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2614     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2615     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2616     { WM_MOVE, sent },
2617     { 0 }
2618 };
2619 /* DestroyWindow for MDI frame window, initially visible */
2620 static const struct message WmDestroyMDIframeSeq[] = {
2621     { HCBT_DESTROYWND, hook },
2622     { 0x0090, sent|optional },
2623     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2624     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2625     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2626     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2627     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
2628     { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2629     { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
2630     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
2631     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2632     { WM_DESTROY, sent },
2633     { WM_NCDESTROY, sent },
2634     { 0 }
2635 };
2636 /* CreateWindow for MDI client window, initially visible */
2637 static const struct message WmCreateMDIclientSeq[] = {
2638     { HCBT_CREATEWND, hook },
2639     { WM_NCCREATE, sent },
2640     { WM_NCCALCSIZE, sent|wparam, 0 },
2641     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2642     { WM_CREATE, sent },
2643     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2644     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2645     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2646     { WM_MOVE, sent },
2647     { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
2648     { WM_SHOWWINDOW, sent|wparam, 1 },
2649     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2650     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2651     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2652     { 0 }
2653 };
2654 /* ShowWindow(SW_SHOW) for MDI client window */
2655 static const struct message WmShowMDIclientSeq[] = {
2656     { WM_SHOWWINDOW, sent|wparam, 1 },
2657     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2658     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2659     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2660     { 0 }
2661 };
2662 /* ShowWindow(SW_HIDE) for MDI client window */
2663 static const struct message WmHideMDIclientSeq[] = {
2664     { WM_SHOWWINDOW, sent|wparam, 0 },
2665     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2666     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
2667     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
2668     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2669     { 0 }
2670 };
2671 /* DestroyWindow for MDI client window, initially visible */
2672 static const struct message WmDestroyMDIclientSeq[] = {
2673     { HCBT_DESTROYWND, hook },
2674     { 0x0090, sent|optional },
2675     { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
2676     { WM_SHOWWINDOW, sent|wparam, 0 },
2677     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2678     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2679     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2680     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2681     { WM_DESTROY, sent },
2682     { WM_NCDESTROY, sent },
2683     { 0 }
2684 };
2685 /* CreateWindow for MDI child window, initially visible */
2686 static const struct message WmCreateMDIchildVisibleSeq[] = {
2687     { HCBT_CREATEWND, hook },
2688     { WM_NCCREATE, sent },
2689     { WM_NCCALCSIZE, sent|wparam, 0 },
2690     { WM_CREATE, sent },
2691     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2692     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2693     { WM_MOVE, sent },
2694     /* Win2k sends wparam set to
2695      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2696      * while Win9x doesn't bother to set child window id according to
2697      * CLIENTCREATESTRUCT.idFirstChild
2698      */
2699     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2700     { WM_SHOWWINDOW, sent|wparam, 1 },
2701     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2702     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2703     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2704     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2705     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2706     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2707     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2708 
2709     /* Win9x: message sequence terminates here. */
2710 
2711     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2712     { HCBT_SETFOCUS, hook }, /* in MDI client */
2713     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2714     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2715     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2716     { WM_SETFOCUS, sent }, /* in MDI client */
2717     { HCBT_SETFOCUS, hook },
2718     { WM_KILLFOCUS, sent }, /* in MDI client */
2719     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2720     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2721     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2722     { WM_SETFOCUS, sent|defwinproc },
2723     { WM_MDIACTIVATE, sent|defwinproc },
2724     { 0 }
2725 };
2726 /* WM_CHILDACTIVATE sent to disabled window */
2727 static const struct message WmChildActivateDisabledWindowSeq[] = {
2728     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2729     { 0 }
2730 };
2731 /* WM_CHILDACTIVATE sent to enabled window */
2732 static const struct message WmChildActivateWindowSeq[] = {
2733     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2734     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 },
2735     { WM_MDIACTIVATE, sent|defwinproc },
2736     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2737     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2738     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2739     { HCBT_SETFOCUS, hook },
2740     { WM_KILLFOCUS, sent|defwinproc },
2741     { WM_SETFOCUS, sent },
2742     { HCBT_SETFOCUS, hook },
2743     { WM_KILLFOCUS, sent },
2744     { WM_SETFOCUS, sent|defwinproc },
2745     { WM_MDIACTIVATE, sent|defwinproc },
2746     { 0 }
2747 };
2748 /* CreateWindow for MDI child window with invisible parent */
2749 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
2750     { HCBT_CREATEWND, hook },
2751     { WM_GETMINMAXINFO, sent },
2752     { WM_NCCREATE, sent },
2753     { WM_NCCALCSIZE, sent|wparam, 0 },
2754     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2755     { WM_CREATE, sent },
2756     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2757     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2758     { WM_MOVE, sent },
2759     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2760     { WM_SHOWWINDOW, sent|wparam, 1 },
2761     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2762     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2763     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2764     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2765 
2766     /* Win9x: message sequence terminates here. */
2767 
2768     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2769     { HCBT_SETFOCUS, hook }, /* in MDI client */
2770     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2771     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2772     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2773     { WM_SETFOCUS, sent }, /* in MDI client */
2774     { HCBT_SETFOCUS, hook },
2775     { WM_KILLFOCUS, sent }, /* in MDI client */
2776     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2777     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2778     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2779     { WM_SETFOCUS, sent|defwinproc },
2780     { WM_MDIACTIVATE, sent|defwinproc },
2781     { 0 }
2782 };
2783 /* DestroyWindow for MDI child window, initially visible */
2784 static const struct message WmDestroyMDIchildVisibleSeq[] = {
2785     { HCBT_DESTROYWND, hook },
2786     /* Win2k sends wparam set to
2787      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2788      * while Win9x doesn't bother to set child window id according to
2789      * CLIENTCREATESTRUCT.idFirstChild
2790      */
2791     { 0x0090, sent|optional },
2792     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2793     { WM_SHOWWINDOW, sent|wparam, 0 },
2794     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2795     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2796     { WM_ERASEBKGND, sent|parent|optional },
2797     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2798 
2799     /* { WM_DESTROY, sent }
2800      * Win9x: message sequence terminates here.
2801      */
2802 
2803     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2804     { WM_KILLFOCUS, sent },
2805     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2806     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2807     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2808     { WM_SETFOCUS, sent }, /* in MDI client */
2809 
2810     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2811     { WM_KILLFOCUS, sent }, /* in MDI client */
2812     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2813     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2814     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2815     { WM_SETFOCUS, sent }, /* in MDI client */
2816 
2817     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2818 
2819     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2820     { WM_KILLFOCUS, sent },
2821     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2822     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2823     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2824     { WM_SETFOCUS, sent }, /* in MDI client */
2825 
2826     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2827     { WM_KILLFOCUS, sent }, /* in MDI client */
2828     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2829     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2830     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2831     { WM_SETFOCUS, sent }, /* in MDI client */
2832 
2833     { WM_DESTROY, sent },
2834 
2835     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2836     { WM_KILLFOCUS, sent },
2837     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2838     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2839     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2840     { WM_SETFOCUS, sent }, /* in MDI client */
2841 
2842     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2843     { WM_KILLFOCUS, sent }, /* in MDI client */
2844     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2845     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2846     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2847     { WM_SETFOCUS, sent }, /* in MDI client */
2848 
2849     { WM_NCDESTROY, sent },
2850     { 0 }
2851 };
2852 /* CreateWindow for MDI child window, initially invisible */
2853 static const struct message WmCreateMDIchildInvisibleSeq[] = {
2854     { HCBT_CREATEWND, hook },
2855     { WM_NCCREATE, sent },
2856     { WM_NCCALCSIZE, sent|wparam, 0 },
2857     { WM_CREATE, sent },
2858     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2859     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2860     { WM_MOVE, sent },
2861     /* Win2k sends wparam set to
2862      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2863      * while Win9x doesn't bother to set child window id according to
2864      * CLIENTCREATESTRUCT.idFirstChild
2865      */
2866     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2867     { 0 }
2868 };
2869 /* DestroyWindow for MDI child window, initially invisible */
2870 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
2871     { HCBT_DESTROYWND, hook },
2872     /* Win2k sends wparam set to
2873      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2874      * while Win9x doesn't bother to set child window id according to
2875      * CLIENTCREATESTRUCT.idFirstChild
2876      */
2877     { 0x0090, sent|optional },
2878     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2879     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2880     { WM_DESTROY, sent },
2881     { WM_NCDESTROY, sent },
2882     /* FIXME: Wine destroys an icon/title window while Windows doesn't */
2883     { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */
2884     { 0 }
2885 };
2886 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
2887 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
2888     { HCBT_CREATEWND, hook },
2889     { WM_NCCREATE, sent },
2890     { WM_NCCALCSIZE, sent|wparam, 0 },
2891     { WM_CREATE, sent },
2892     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2893     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2894     { WM_MOVE, sent },
2895     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2896     { WM_GETMINMAXINFO, sent },
2897     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED  },
2898     { WM_NCCALCSIZE, sent|wparam, 1 },
2899     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2900     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2901      /* in MDI frame */
2902     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2903     { WM_NCCALCSIZE, sent|wparam, 1 },
2904     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2905     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2906     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2907     /* Win2k sends wparam set to
2908      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2909      * while Win9x doesn't bother to set child window id according to
2910      * CLIENTCREATESTRUCT.idFirstChild
2911      */
2912     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2913     { WM_SHOWWINDOW, sent|wparam, 1 },
2914     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2915     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2916     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2917     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2918     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2919     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2920     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_FRAMECHANGED },
2921 
2922     /* Win9x: message sequence terminates here. */
2923 
2924     { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
2925     { HCBT_SETFOCUS, hook|optional }, /* in MDI client */
2926     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2927     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2928     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2929     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2930     { HCBT_SETFOCUS, hook|optional },
2931     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
2932     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2933     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2934     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2935     { WM_SETFOCUS, sent|defwinproc|optional },
2936     { WM_MDIACTIVATE, sent|defwinproc|optional },
2937      /* in MDI frame */
2938     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2939     { WM_NCCALCSIZE, sent|wparam, 1 },
2940     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2941     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2942     { 0 }
2943 };
2944 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
2945 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
2946     /* restore the 1st MDI child */
2947     { WM_SETREDRAW, sent|wparam, 0 },
2948     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2949     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2950     { WM_NCCALCSIZE, sent|wparam, 1 },
2951     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2952     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2953     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2954      /* in MDI frame */
2955     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2956     { WM_NCCALCSIZE, sent|wparam, 1 },
2957     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2958     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2959     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2960     { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
2961     /* create the 2nd MDI child */
2962     { HCBT_CREATEWND, hook },
2963     { WM_NCCREATE, sent },
2964     { WM_NCCALCSIZE, sent|wparam, 0 },
2965     { WM_CREATE, sent },
2966     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2967     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2968     { WM_MOVE, sent },
2969     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2970     { WM_GETMINMAXINFO, sent },
2971     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2972     { WM_NCCALCSIZE, sent|wparam, 1 },
2973     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2974     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2975     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2976      /* in MDI frame */
2977     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2978     { WM_NCCALCSIZE, sent|wparam, 1 },
2979     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2980     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2981     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2982     /* Win2k sends wparam set to
2983      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2984      * while Win9x doesn't bother to set child window id according to
2985      * CLIENTCREATESTRUCT.idFirstChild
2986      */
2987     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2988     { WM_SHOWWINDOW, sent|wparam, 1 },
2989     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2990     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2991     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2992     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2993     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2994     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2995 
2996     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2997     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2998 
2999     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3000 
3001     /* Win9x: message sequence terminates here. */
3002 
3003     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3004     { HCBT_SETFOCUS, hook },
3005     { WM_KILLFOCUS, sent|defwinproc|optional }, /* in the 1st MDI child */
3006     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
3007     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3008     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3009     { WM_SETFOCUS, sent }, /* in MDI client */
3010     { HCBT_SETFOCUS, hook },
3011     { WM_KILLFOCUS, sent }, /* in MDI client */
3012     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3013     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3014     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3015     { WM_SETFOCUS, sent|defwinproc },
3016 
3017     { WM_MDIACTIVATE, sent|defwinproc },
3018      /* in MDI frame */
3019     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3020     { WM_NCCALCSIZE, sent|wparam, 1 },
3021     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3022     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3023     { 0 }
3024 };
3025 /* WM_MDICREATE MDI child window, initially visible and maximized */
3026 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
3027     { WM_MDICREATE, sent },
3028     { HCBT_CREATEWND, hook },
3029     { WM_NCCREATE, sent },
3030     { WM_NCCALCSIZE, sent|wparam, 0 },
3031     { WM_CREATE, sent },
3032     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3033     { WM_SIZE, sent|wparam, SIZE_RESTORED },
3034     { WM_MOVE, sent },
3035     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3036     { WM_GETMINMAXINFO, sent },
3037     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3038     { WM_NCCALCSIZE, sent|wparam, 1 },
3039     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3040     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3041 
3042      /* in MDI frame */
3043     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3044     { WM_NCCALCSIZE, sent|wparam, 1 },
3045     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3046     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3047     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3048 
3049     /* Win2k sends wparam set to
3050      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3051      * while Win9x doesn't bother to set child window id according to
3052      * CLIENTCREATESTRUCT.idFirstChild
3053      */
3054     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3055     { WM_SHOWWINDOW, sent|wparam, 1 },
3056     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3057 
3058     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3059 
3060     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3061     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
3062     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
3063 
3064     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3065     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3066 
3067     /* Win9x: message sequence terminates here. */
3068 
3069     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3070     { WM_SETFOCUS, sent|optional }, /* in MDI client */
3071     { HCBT_SETFOCUS, hook }, /* in MDI client */
3072     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3073     { WM_IME_NOTIFY, sent|wparam|optional, 2 },
3074     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
3075     { WM_SETFOCUS, sent|optional }, /* in MDI client */
3076     { HCBT_SETFOCUS, hook|optional },
3077     { WM_KILLFOCUS, sent }, /* in MDI client */
3078     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3079     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3080     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3081     { WM_SETFOCUS, sent|defwinproc },
3082 
3083     { WM_MDIACTIVATE, sent|defwinproc },
3084 
3085      /* in MDI child */
3086     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3087     { WM_NCCALCSIZE, sent|wparam, 1 },
3088     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3089     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
3090 
3091      /* in MDI frame */
3092     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3093     { WM_NCCALCSIZE, sent|wparam, 1 },
3094     { 0x0093, sent|defwinproc|optional },
3095     { 0x0093, sent|defwinproc|optional },
3096     { 0x0093, sent|defwinproc|optional },
3097     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3098     { WM_MOVE, sent|defwinproc },
3099     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3100 
3101      /* in MDI client */
3102     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3103     { WM_NCCALCSIZE, sent|wparam, 1 },
3104     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3105     { WM_SIZE, sent|wparam, SIZE_RESTORED },
3106 
3107      /* in MDI child */
3108     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3109     { WM_NCCALCSIZE, sent|wparam, 1 },
3110     { 0x0093, sent|optional },
3111     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3112     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3113 
3114     { 0x0093, sent|optional },
3115     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3116     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3117     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
3118     { 0x0093, sent|defwinproc|optional },
3119     { 0x0093, sent|defwinproc|optional },
3120     { 0x0093, sent|defwinproc|optional },
3121     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3122     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3123 
3124     { 0 }
3125 };
3126 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
3127 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
3128     { HCBT_CREATEWND, hook },
3129     { WM_GETMINMAXINFO, sent },
3130     { WM_NCCREATE, sent },
3131     { WM_NCCALCSIZE, sent|wparam, 0 },
3132     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
3133     { WM_CREATE, sent },
3134     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3135     { WM_SIZE, sent|wparam, SIZE_RESTORED },
3136     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOZORDER }, /* MDI frame */
3137     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI frame */
3138     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOZORDER }, /* MDI frame */
3139     { WM_MOVE, sent },
3140     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3141     { WM_GETMINMAXINFO, sent },
3142     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3143     { WM_GETMINMAXINFO, sent|defwinproc },
3144     { WM_NCCALCSIZE, sent|wparam, 1 },
3145     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_STATECHANGED },
3146     { WM_MOVE, sent|defwinproc },
3147     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3148      /* in MDI frame */
3149     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3150     { WM_NCCALCSIZE, sent|wparam, 1 },
3151     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3152     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3153     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
3154     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3155     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3156     /* Win2k sends wparam set to
3157      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3158      * while Win9x doesn't bother to set child window id according to
3159      * CLIENTCREATESTRUCT.idFirstChild
3160      */
3161     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3162     { 0 }
3163 };
3164 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
3165 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
3166     { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
3167     { HCBT_SYSCOMMAND, hook },
3168     { WM_CLOSE, sent|defwinproc },
3169     { WM_MDIDESTROY, sent }, /* in MDI client */
3170 
3171     /* bring the 1st MDI child to top */
3172     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
3173     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
3174 
3175     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3176 
3177     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
3178     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
3179     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
3180 
3181     /* maximize the 1st MDI child */
3182     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3183     { WM_GETMINMAXINFO, sent|defwinproc },
3184     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED },
3185     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
3186     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
3187     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3188     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3189 
3190     /* restore the 2nd MDI child */
3191     { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
3192     { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
3193     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
3194     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
3195 
3196     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3197 
3198     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3199     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3200 
3201     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3202 
3203     { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
3204      /* in MDI frame */
3205     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3206     { WM_NCCALCSIZE, sent|wparam, 1 },
3207     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3208     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3209     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3210 
3211     /* bring the 1st MDI child to top */
3212     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3213     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3214     { HCBT_SETFOCUS, hook },
3215     { WM_KILLFOCUS, sent|defwinproc },
3216     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
3217     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3218     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3219     { WM_SETFOCUS, sent }, /* in MDI client */
3220     { HCBT_SETFOCUS, hook },
3221     { WM_KILLFOCUS, sent }, /* in MDI client */
3222     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3223     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3224     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3225     { WM_SETFOCUS, sent|defwinproc },
3226     { WM_MDIACTIVATE, sent|defwinproc },
3227     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3228 
3229     /* apparently ShowWindow(SW_SHOW) on an MDI client */
3230     { WM_SHOWWINDOW, sent|wparam, 1 },
3231     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3232     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3233     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3234     { WM_MDIREFRESHMENU, sent },
3235 
3236     { HCBT_DESTROYWND, hook },
3237     /* Win2k sends wparam set to
3238      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3239      * while Win9x doesn't bother to set child window id according to
3240      * CLIENTCREATESTRUCT.idFirstChild
3241      */
3242     { 0x0090, sent|defwinproc|optional },
3243     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3244     { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
3245     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3246     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3247     { WM_ERASEBKGND, sent|parent|optional },
3248     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3249 
3250     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
3251     { WM_DESTROY, sent|defwinproc },
3252     { WM_NCDESTROY, sent|defwinproc },
3253     { 0 }
3254 };
3255 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
3256 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
3257     { WM_MDIDESTROY, sent }, /* in MDI client */
3258     { WM_SHOWWINDOW, sent|wparam, 0 },
3259     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3260     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3261     { WM_ERASEBKGND, sent|parent|optional },
3262     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3263 
3264     { HCBT_SETFOCUS, hook },
3265     { WM_KILLFOCUS, sent },
3266     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3267     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3268     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3269     { WM_SETFOCUS, sent }, /* in MDI client */
3270     { HCBT_SETFOCUS, hook },
3271     { WM_KILLFOCUS, sent }, /* in MDI client */
3272     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3273     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3274     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3275     { WM_SETFOCUS, sent },
3276 
3277      /* in MDI child */
3278     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3279     { WM_NCCALCSIZE, sent|wparam, 1 },
3280     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3281     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3282 
3283      /* in MDI frame */
3284     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3285     { WM_NCCALCSIZE, sent|wparam, 1 },
3286     { 0x0093, sent|defwinproc|optional },
3287     { 0x0093, sent|defwinproc|optional },
3288     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3289     { WM_MOVE, sent|defwinproc },
3290     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3291 
3292      /* in MDI client */
3293     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3294     { WM_NCCALCSIZE, sent|wparam, 1 },
3295     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3296     { WM_SIZE, sent|wparam, SIZE_RESTORED },
3297 
3298      /* in MDI child */
3299     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3300     { WM_NCCALCSIZE, sent|wparam, 1 },
3301     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3302     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3303 
3304      /* in MDI child */
3305     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3306     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3307     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3308     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3309 
3310      /* in MDI frame */
3311     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3312     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3313     { 0x0093, sent|defwinproc|optional },
3314     { 0x0093, sent|defwinproc|optional },
3315     { 0x0093, sent|defwinproc|optional },
3316     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3317     { WM_MOVE, sent|defwinproc },
3318     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3319 
3320      /* in MDI client */
3321     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3322     { WM_NCCALCSIZE, sent|wparam, 1 },
3323     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3324     { WM_SIZE, sent|wparam, SIZE_RESTORED },
3325 
3326      /* in MDI child */
3327     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3328     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3329     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3330     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3331     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3332     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3333 
3334     { 0x0093, sent|defwinproc|optional },
3335     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
3336     { 0x0093, sent|defwinproc|optional },
3337     { 0x0093, sent|defwinproc|optional },
3338     { 0x0093, sent|defwinproc|optional },
3339     { 0x0093, sent|optional },
3340 
3341     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3342     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3343     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3344     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3345     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3346 
3347      /* in MDI frame */
3348     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3349     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3350     { 0x0093, sent|defwinproc|optional },
3351     { 0x0093, sent|defwinproc|optional },
3352     { 0x0093, sent|defwinproc|optional },
3353     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3354     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3355     { 0x0093, sent|optional },
3356 
3357     { WM_NCACTIVATE, sent|wparam, 0 },
3358     { WM_MDIACTIVATE, sent },
3359 
3360     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
3361     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
3362     { WM_NCCALCSIZE, sent|wparam, 1 },
3363 
3364     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3365 
3366     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3367     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3368     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3369 
3370      /* in MDI child */
3371     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3372     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3373     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3374     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3375 
3376      /* in MDI frame */
3377     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3378     { WM_NCCALCSIZE, sent|wparam, 1 },
3379     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3380     { WM_MOVE, sent|defwinproc },
3381     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3382 
3383      /* in MDI client */
3384     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3385     { WM_NCCALCSIZE, sent|wparam, 1 },
3386     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3387     { WM_SIZE, sent|wparam, SIZE_RESTORED },
3388     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3389     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
3390     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3391     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3392     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3393 
3394     { HCBT_SETFOCUS, hook },
3395     { WM_KILLFOCUS, sent },
3396     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3397     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3398     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3399     { WM_SETFOCUS, sent }, /* in MDI client */
3400 
3401     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
3402 
3403     { HCBT_DESTROYWND, hook },
3404     /* Win2k sends wparam set to
3405      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3406      * while Win9x doesn't bother to set child window id according to
3407      * CLIENTCREATESTRUCT.idFirstChild
3408      */
3409     { 0x0090, sent|optional },
3410     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3411 
3412     { WM_SHOWWINDOW, sent|wparam, 0 },
3413     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3414     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3415     { WM_ERASEBKGND, sent|parent|optional },
3416     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3417 
3418     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
3419     { WM_DESTROY, sent },
3420     { WM_NCDESTROY, sent },
3421     { 0 }
3422 };
3423 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
3424 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
3425     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3426     { WM_GETMINMAXINFO, sent },
3427     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3428     { WM_NCCALCSIZE, sent|wparam, 1 },
3429     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3430     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3431 
3432     { WM_WINDOWPOSCHANGING, sent|wparam|optional|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3433     { WM_NCACTIVATE, sent|wparam|optional|defwinproc, 1 },
3434     { HCBT_SETFOCUS, hook|optional },
3435     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3436     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3437     { WM_SETFOCUS, sent|optional }, /* in MDI client */
3438     { HCBT_SETFOCUS, hook|optional },
3439     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3440     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3441     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3442     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3443     { WM_SETFOCUS, sent|optional|defwinproc },
3444     { WM_MDIACTIVATE, sent|optional|defwinproc },
3445     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3446     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3447      /* in MDI frame */
3448     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3449     { WM_NCCALCSIZE, sent|wparam, 1 },
3450     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3451     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3452     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3453     { 0 }
3454 };
3455 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
3456 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
3457     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3458     { WM_GETMINMAXINFO, sent },
3459     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
3460     { WM_GETMINMAXINFO, sent|defwinproc },
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|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3466     { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 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|defwinproc|optional },
3477     { WM_MDIACTIVATE, sent|defwinproc|optional },
3478     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3479     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3480     { WM_SIZE, sent|defwinproc|optional },
3481     { 0 }
3482 };
3483 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
3484 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
3485     { WM_MDIMAXIMIZE, sent }, /* in MDI client */
3486     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3487     { WM_GETMINMAXINFO, sent },
3488     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3489     { WM_GETMINMAXINFO, sent|defwinproc },
3490     { WM_NCCALCSIZE, sent|wparam, 1 },
3491     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
3492     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3493     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
3494     { WM_MOVE, sent|defwinproc },
3495     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3496 
3497     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3498     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3499     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3500     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3501     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3502     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3503      /* in MDI frame */
3504     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3505     { WM_NCCALCSIZE, sent|wparam, 1 },
3506     { 0x0093, sent|defwinproc|optional },
3507     { 0x0094, sent|defwinproc|optional },
3508     { 0x0094, sent|defwinproc|optional },
3509     { 0x0094, sent|defwinproc|optional },
3510     { 0x0094, sent|defwinproc|optional },
3511     { 0x0093, sent|defwinproc|optional },
3512     { 0x0093, sent|defwinproc|optional },
3513     { 0x0091, sent|defwinproc|optional },
3514     { 0x0092, sent|defwinproc|optional },
3515     { 0x0092, sent|defwinproc|optional },
3516     { 0x0092, sent|defwinproc|optional },
3517     { 0x0092, sent|defwinproc|optional },
3518     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3519     { WM_MOVE, sent|defwinproc },
3520     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3521     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
3522      /* in MDI client */
3523     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3524     { WM_NCCALCSIZE, sent|wparam, 1 },
3525     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3526     { WM_SIZE, sent|wparam, SIZE_RESTORED },
3527      /* in MDI child */
3528     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3529     { WM_GETMINMAXINFO, sent|defwinproc },
3530     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3531     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3532     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3533     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
3534     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3535     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3536     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3537     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3538      /* in MDI frame */
3539     { 0x0093, sent|optional },
3540     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3541     { 0x0093, sent|defwinproc|optional },
3542     { 0x0093, sent|defwinproc|optional },
3543     { 0x0093, sent|defwinproc|optional },
3544     { 0x0091, sent|defwinproc|optional },
3545     { 0x0092, sent|defwinproc|optional },
3546     { 0x0092, sent|defwinproc|optional },
3547     { 0x0092, sent|defwinproc|optional },
3548     { 0x0092, sent|defwinproc|optional },
3549     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3550     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3551     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3552     { 0 }
3553 };
3554 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
3555 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
3556     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3557     { WM_GETMINMAXINFO, sent },
3558     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3559     { WM_NCCALCSIZE, sent|wparam, 1 },
3560     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3561     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3562     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3563      /* in MDI frame */
3564     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3565     { WM_NCCALCSIZE, sent|wparam, 1 },
3566     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3567     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3568     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3569     { 0 }
3570 };
3571 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
3572 static const struct message WmRestoreMDIchildVisibleSeq[] = {
3573     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3574     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3575     { WM_NCCALCSIZE, sent|wparam, 1 },
3576     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3577     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3578     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3579      /* in MDI frame */
3580     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3581     { WM_NCCALCSIZE, sent|wparam, 1 },
3582     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3583     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3584     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3585     { 0 }
3586 };
3587 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
3588 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
3589     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3590     { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
3591     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3592     { WM_NCCALCSIZE, sent|wparam, 1 },
3593     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3594     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3595     { WM_MOVE, sent|defwinproc },
3596     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3597     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3598     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3599     { HCBT_SETFOCUS, hook },
3600     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3601     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
3602     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3603     { WM_SETFOCUS, sent },
3604     { 0 }
3605 };
3606 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
3607 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
3608     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
3609     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3610     { WM_NCCALCSIZE, sent|wparam, 1 },
3611     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3612     { WM_MOVE, sent|defwinproc },
3613     { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
3614     { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
3615     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3616     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3617     /* FIXME: Wine creates an icon/title window while Windows doesn't */
3618     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */
3619     { 0 }
3620 };
3621 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
3622 static const struct message WmRestoreMDIchildInvisibleSeq[] = {
3623     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3624     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED  },
3625     { WM_NCCALCSIZE, sent|wparam, 1 },
3626     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3627     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3628     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3629     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3630      /* in MDI frame */
3631     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3632     { WM_NCCALCSIZE, sent|wparam, 1 },
3633     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3634     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3635     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3636     { 0 }
3637 };
3638 
3639 static HWND mdi_client;
3640 static WNDPROC old_mdi_client_proc;
3641 
3642 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3643 {
3644     struct recvd_message msg;
3645 
3646     /* do not log painting messages */
3647     if (message != WM_PAINT &&
3648         message != WM_NCPAINT &&
3649         message != WM_SYNCPAINT &&
3650         message != WM_ERASEBKGND &&
3651         message != WM_NCHITTEST &&
3652         message != WM_GETTEXT &&
3653         message != WM_MDIGETACTIVE &&
3654         !ignore_message( message ))
3655     {
3656         msg.hwnd = hwnd;
3657         msg.message = message;
3658         msg.flags = sent|wparam|lparam;
3659         msg.wParam = wParam;
3660         msg.lParam = lParam;
3661         msg.descr = "mdi client";
3662         add_message(&msg);
3663     }
3664 
3665     return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
3666 }
3667 
3668 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3669 {
3670     static LONG defwndproc_counter = 0;
3671     LRESULT ret;
3672     struct recvd_message msg;
3673 
3674     /* do not log painting messages */
3675     if (message != WM_PAINT &&
3676         message != WM_NCPAINT &&
3677         message != WM_SYNCPAINT &&
3678         message != WM_ERASEBKGND &&
3679         message != WM_NCHITTEST &&
3680         message != WM_GETTEXT &&
3681         !ignore_message( message ))
3682     {
3683         switch (message)
3684         {
3685             case WM_MDIACTIVATE:
3686             {
3687                 HWND active, client = GetParent(hwnd);
3688 
3689                 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
3690 
3691                 if (hwnd == (HWND)lParam) /* if we are being activated */
3692                     ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
3693                 else
3694                     ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
3695                 break;
3696             }
3697         }
3698 
3699         msg.hwnd = hwnd;
3700         msg.message = message;
3701         msg.flags = sent|wparam|lparam;
3702         if (defwndproc_counter) msg.flags |= defwinproc;
3703         msg.wParam = wParam;
3704         msg.lParam = lParam;
3705         msg.descr = "mdi child";
3706         add_message(&msg);
3707     }
3708 
3709     defwndproc_counter++;
3710     ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
3711     defwndproc_counter--;
3712 
3713     return ret;
3714 }
3715 
3716 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3717 {
3718     static LONG defwndproc_counter = 0;
3719     LRESULT ret;
3720     struct recvd_message msg;
3721 
3722     /* do not log painting messages */
3723     if (message != WM_PAINT &&
3724         message != WM_NCPAINT &&
3725         message != WM_SYNCPAINT &&
3726         message != WM_ERASEBKGND &&
3727         message != WM_NCHITTEST &&
3728         message != WM_GETTEXT &&
3729         !ignore_message( message ))
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 frame";
3738         add_message(&msg);
3739     }
3740 
3741     defwndproc_counter++;
3742     ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
3743     defwndproc_counter--;
3744 
3745     return ret;
3746 }
3747 
3748 static BOOL mdi_RegisterWindowClasses(void)
3749 {
3750     WNDCLASSA cls;
3751 
3752     cls.style = 0;
3753     cls.lpfnWndProc = mdi_frame_wnd_proc;
3754     cls.cbClsExtra = 0;
3755     cls.cbWndExtra = 0;
3756     cls.hInstance = GetModuleHandleA(0);
3757     cls.hIcon = 0;
3758     cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
3759     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
3760     cls.lpszMenuName = NULL;
3761     cls.lpszClassName = "MDI_frame_class";
3762     if (!RegisterClassA(&cls)) return FALSE;
3763 
3764     cls.lpfnWndProc = mdi_child_wnd_proc;
3765     cls.lpszClassName = "MDI_child_class";
3766     if (!RegisterClassA(&cls)) return FALSE;
3767 
3768     if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
3769     old_mdi_client_proc = cls.lpfnWndProc;
3770     cls.hInstance = GetModuleHandleA(0);
3771     cls.lpfnWndProc = mdi_client_hook_proc;
3772     cls.lpszClassName = "MDI_client_class";
3773     if (!RegisterClassA(&cls)) assert(0);
3774 
3775     return TRUE;
3776 }
3777 
3778 static void test_mdi_messages(void)
3779 {
3780     MDICREATESTRUCTA mdi_cs;
3781     CLIENTCREATESTRUCT client_cs;
3782     HWND mdi_frame, mdi_child, mdi_child2, active_child;
3783     BOOL zoomed;
3784     RECT rc;
3785     HMENU hMenu = CreateMenu();
3786     LONG val;
3787 
3788     if (!mdi_RegisterWindowClasses()) assert(0);
3789 
3790     flush_sequence();
3791 
3792     trace("creating MDI frame window\n");
3793     mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
3794                                 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
3795                                 WS_MAXIMIZEBOX | WS_VISIBLE,
3796                                 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
3797                                 GetDesktopWindow(), hMenu,
3798                                 GetModuleHandleA(0), NULL);
3799     assert(mdi_frame);
3800     ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
3801 
3802     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3803     ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
3804 
3805     trace("creating MDI client window\n");
3806     GetClientRect(mdi_frame, &rc);
3807     client_cs.hWindowMenu = 0;
3808     client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
3809     mdi_client = CreateWindowExA(0, "MDI_client_class",
3810                                  NULL,
3811                                  WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
3812                                  rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
3813                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3814     assert(mdi_client);
3815     SetWindowLongA(mdi_client, 0, 0xdeadbeef);
3816 
3817     ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
3818     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3819     ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
3820 
3821     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3822     ok(!active_child, "wrong active MDI child %p\n", active_child);
3823     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3824 
3825     SetFocus(0);
3826     flush_sequence();
3827 
3828     trace("creating invisible MDI child window\n");
3829     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3830                                 WS_CHILD,
3831                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3832                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3833     assert(mdi_child);
3834 
3835     flush_sequence();
3836     ShowWindow(mdi_child, SW_SHOWNORMAL);
3837     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
3838 
3839     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3840     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3841 
3842     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3843     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3844 
3845     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3846     ok(!active_child, "wrong active MDI child %p\n", active_child);
3847     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3848 
3849     ShowWindow(mdi_child, SW_HIDE);
3850     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
3851     flush_sequence();
3852 
3853     ShowWindow(mdi_child, SW_SHOW);
3854     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
3855 
3856     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3857     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3858 
3859     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3860     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3861 
3862     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3863     ok(!active_child, "wrong active MDI child %p\n", active_child);
3864     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3865 
3866     DestroyWindow(mdi_child);
3867     flush_sequence();
3868 
3869     trace("creating visible MDI child window\n");
3870     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3871                                 WS_CHILD | WS_VISIBLE,
3872                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3873                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3874     assert(mdi_child);
3875     ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
3876 
3877     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3878     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3879 
3880     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3881     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3882 
3883     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3884     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3885     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3886     flush_sequence();
3887 
3888     DestroyWindow(mdi_child);
3889     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3890 
3891     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3892     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3893 
3894     /* Win2k: MDI client still returns a just destroyed child as active
3895      * Win9x: MDI client returns 0
3896      */
3897     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3898     ok(active_child == mdi_child || /* win2k */
3899        !active_child, /* win9x */
3900        "wrong active MDI child %p\n", active_child);
3901     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3902 
3903     flush_sequence();
3904 
3905     trace("creating invisible MDI child window\n");
3906     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3907                                 WS_CHILD,
3908                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3909                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3910     assert(mdi_child2);
3911     ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
3912 
3913     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
3914     ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
3915 
3916     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3917     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3918 
3919     /* Win2k: MDI client still returns a just destroyed child as active
3920      * Win9x: MDI client returns mdi_child2
3921      */
3922     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3923     ok(active_child == mdi_child || /* win2k */
3924        active_child == mdi_child2, /* win9x */
3925        "wrong active MDI child %p\n", active_child);
3926     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3927     flush_sequence();
3928 
3929     ShowWindow(mdi_child2, SW_MAXIMIZE);
3930     ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
3931 
3932     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3933     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3934 
3935     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3936     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3937     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3938     flush_sequence();
3939 
3940     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3941     ok(GetFocus() == mdi_child2 || /* win2k */
3942        GetFocus() == 0, /* win9x */
3943        "wrong focus window %p\n", GetFocus());
3944 
3945     SetFocus(0);
3946     flush_sequence();
3947 
3948     ShowWindow(mdi_child2, SW_HIDE);
3949     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3950 
3951     ShowWindow(mdi_child2, SW_RESTORE);
3952     ok_sequence(WmRestoreMDIchildInvisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
3953     flush_sequence();
3954 
3955     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3956     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3957 
3958     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3959     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3960     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3961     flush_sequence();
3962 
3963     SetFocus(0);
3964     flush_sequence();
3965 
3966     ShowWindow(mdi_child2, SW_HIDE);
3967     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3968 
3969     ShowWindow(mdi_child2, SW_SHOW);
3970     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
3971 
3972     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3973     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3974 
3975     ShowWindow(mdi_child2, SW_MAXIMIZE);
3976     ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
3977 
3978     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3979     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3980 
3981     ShowWindow(mdi_child2, SW_RESTORE);
3982     ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
3983 
3984     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3985     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3986 
3987     ShowWindow(mdi_child2, SW_MINIMIZE);
3988     ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", FALSE);
3989 
3990     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3991     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3992 
3993     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3994     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3995     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3996     flush_sequence();
3997 
3998     ShowWindow(mdi_child2, SW_RESTORE);
3999     ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", FALSE);
4000 
4001     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4002     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4003 
4004     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4005     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4006     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4007     flush_sequence();
4008 
4009     SetFocus(0);
4010     flush_sequence();
4011 
4012     ShowWindow(mdi_child2, SW_HIDE);
4013     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
4014 
4015     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4016     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4017 
4018     DestroyWindow(mdi_child2);
4019     ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
4020 
4021     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4022     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4023 
4024     trace("Testing WM_CHILDACTIVATE\n");
4025 
4026     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4027                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_DISABLED,
4028                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4029                                 mdi_client, 0, GetModuleHandleA(0), NULL);
4030 
4031     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4032                                  WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX,
4033                                  0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4034                                  mdi_client, 0, GetModuleHandleA(0), NULL);
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 
4040     flush_sequence();
4041     SendMessageW(mdi_child, WM_CHILDACTIVATE, 0, 0);
4042     ok_sequence(WmChildActivateDisabledWindowSeq, "WM_CHILDACTIVATE sent to disabled window", FALSE);
4043 
4044     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4045     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4046     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4047     flush_sequence();
4048 
4049     EnableWindow(mdi_child, TRUE);
4050 
4051     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4052     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4053     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4054 
4055     flush_sequence();
4056     SendMessageW(mdi_child, WM_CHILDACTIVATE, 0, 0);
4057     ok_sequence(WmChildActivateWindowSeq, "WM_CHILDACTIVATE sent to enabled window", FALSE);
4058 
4059     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4060     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4061     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4062     flush_sequence();
4063 
4064     DestroyWindow(mdi_child);
4065     DestroyWindow(mdi_child2);
4066     flush_sequence();
4067 
4068     /* test for maximized MDI children */
4069     trace("creating maximized visible MDI child window 1\n");
4070     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4071                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4072                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4073                                 mdi_client, 0, GetModuleHandleA(0), NULL);
4074     assert(mdi_child);
4075     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
4076     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4077 
4078     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4079     ok(GetFocus() == mdi_child || /* win2k */
4080        GetFocus() == 0, /* win9x */
4081        "wrong focus window %p\n", GetFocus());
4082 
4083     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4084     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4085     ok(zoomed, "wrong zoomed state %d\n", zoomed);
4086     flush_sequence();
4087 
4088     trace("creating maximized visible MDI child window 2\n");
4089     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4090                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4091                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4092                                 mdi_client, 0, GetModuleHandleA(0), NULL);
4093     assert(mdi_child2);
4094     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
4095     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
4096     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4097 
4098     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4099     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4100 
4101     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4102     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4103     ok(zoomed, "wrong zoomed state %d\n", zoomed);
4104     flush_sequence();
4105 
4106     trace("destroying maximized visible MDI child window 2\n");
4107     DestroyWindow(mdi_child2);
4108     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
4109 
4110     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4111 
4112     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4113     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4114 
4115     /* Win2k: MDI client still returns a just destroyed child as active
4116      * Win9x: MDI client returns 0
4117      */
4118     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4119     ok(active_child == mdi_child2 || /* win2k */
4120        !active_child, /* win9x */
4121        "wrong active MDI child %p\n", active_child);
4122     flush_sequence();
4123 
4124     ShowWindow(mdi_child, SW_MAXIMIZE);
4125     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4126     flush_sequence();
4127 
4128     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4129     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4130 
4131     trace("re-creating maximized visible MDI child window 2\n");
4132     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4133                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4134                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4135                                 mdi_client, 0, GetModuleHandleA(0), NULL);
4136     assert(mdi_child2);
4137     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
4138     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
4139     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4140 
4141     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4142     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4143 
4144     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4145     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4146     ok(zoomed, "wrong zoomed state %d\n", zoomed);
4147     flush_sequence();
4148 
4149     SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
4150     ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
4151     ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
4152 
4153     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4154     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4155     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4156 
4157     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4158     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4159     ok(zoomed, "wrong zoomed state %d\n", zoomed);
4160     flush_sequence();
4161 
4162     DestroyWindow(mdi_child);
4163     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
4164 
4165     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4166     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4167 
4168     /* Win2k: MDI client still returns a just destroyed child as active
4169      * Win9x: MDI client returns 0
4170      */
4171     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4172     ok(active_child == mdi_child || /* win2k */
4173        !active_child, /* win9x */
4174        "wrong active MDI child %p\n", active_child);
4175     flush_sequence();
4176 
4177     trace("creating maximized invisible MDI child window\n");
4178     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4179                                 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
4180                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4181                                 mdi_client, 0, GetModuleHandleA(0), NULL);
4182     assert(mdi_child2);
4183     ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", FALSE);
4184     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
4185     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
4186     ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
4187 
4188     /* Win2k: MDI client still returns a just destroyed child as active
4189      * Win9x: MDI client returns 0
4190      */
4191     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4192     ok(active_child == mdi_child || /* win2k */
4193        !active_child || active_child == mdi_child2, /* win9x */
4194        "wrong active MDI child %p\n", active_child);
4195     flush_sequence();
4196 
4197     trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
4198     ShowWindow(mdi_child2, SW_MAXIMIZE);
4199     ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
4200     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
4201     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4202     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
4203 
4204     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4205     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4206     ok(zoomed, "wrong zoomed state %d\n", zoomed);
4207     flush_sequence();
4208 
4209     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
4210     flush_sequence();
4211 
4212     /* end of test for maximized MDI children */
4213     SetFocus(0);
4214     flush_sequence();
4215     trace("creating maximized visible MDI child window 1(Switch test)\n");
4216     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4217                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4218                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4219                                 mdi_client, 0, GetModuleHandleA(0), NULL);
4220     assert(mdi_child);
4221     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE);
4222     ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n");
4223 
4224     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
4225     ok(GetFocus() == mdi_child || /* win2k */
4226        GetFocus() == 0, /* win9x */
4227        "wrong focus window %p(Switch test)\n", GetFocus());
4228 
4229     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4230     ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
4231     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
4232     flush_sequence();
4233 
4234     trace("creating maximized visible MDI child window 2(Switch test)\n");
4235     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4236                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4237                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4238                                 mdi_client, 0, GetModuleHandleA(0), NULL);
4239     assert(mdi_child2);
4240     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child window (Switch test)", TRUE);
4241 
4242     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n");
4243     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized(Switch test)\n");
4244 
4245     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
4246     ok(GetFocus() == mdi_child2, "wrong focus window %p(Switch test)\n", GetFocus());
4247 
4248     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4249     ok(active_child == mdi_child2, "wrong active MDI child %p(Switch test)\n", active_child);
4250     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
4251     flush_sequence();
4252 
4253     trace("Switch child window.\n");
4254     SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0);
4255     ok_sequence(WmSwitchChild, "Child did not switch correctly", TRUE);
4256     trace("end of test for switch maximized MDI children\n");
4257     flush_sequence();
4258 
4259     /* Prepare for switching test of not maximized MDI children  */
4260     ShowWindow( mdi_child, SW_NORMAL );
4261     ok(!IsZoomed(mdi_child), "wrong zoomed state for %p(Switch test)\n", mdi_child);
4262     ok(!IsZoomed(mdi_child2), "wrong zoomed state for %p(Switch test)\n", mdi_child2);
4263     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
4264     ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
4265     flush_sequence();
4266 
4267     SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child2, 0);
4268     ok_sequence(WmSwitchNotMaximizedChild, "Not maximized child did not switch correctly", FALSE);
4269     trace("end of test for switch not maximized MDI children\n");
4270     flush_sequence();
4271 
4272     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
4273     flush_sequence();
4274 
4275     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
4276     flush_sequence();
4277 
4278     SetFocus(0);
4279     flush_sequence();
4280     /* end of tests for switch maximized/not maximized MDI children */
4281 
4282     mdi_cs.szClass = "MDI_child_Class";
4283     mdi_cs.szTitle = "MDI child";
4284     mdi_cs.hOwner = GetModuleHandleA(0);
4285     mdi_cs.x = 0;
4286     mdi_cs.y = 0;
4287     mdi_cs.cx = CW_USEDEFAULT;
4288     mdi_cs.cy = CW_USEDEFAULT;
4289     mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
4290     mdi_cs.lParam = 0;
4291     mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
4292     ok(mdi_child != 0, "MDI child creation failed\n");
4293     ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
4294 
4295     ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
4296 
4297     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4298     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4299 
4300     ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
4301     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4302     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4303 
4304     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4305     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4306     ok(zoomed, "wrong zoomed state %d\n", zoomed);
4307     flush_sequence();
4308 
4309     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
4310     ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
4311 
4312     ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
4313     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4314     ok(!active_child, "wrong active MDI child %p\n", active_child);
4315 
4316     SetFocus(0);
4317     flush_sequence();
4318 
4319     val = GetWindowLongA(mdi_client, 0);
4320     ok(val == 0xdeadbeef || broken(val == 0) /* >= Win Vista */, "Expected 0xdeadbeef, got 0x%x\n", val);
4321     DestroyWindow(mdi_client);
4322     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
4323 
4324     /* test maximization of MDI child with invisible parent */
4325     client_cs.hWindowMenu = 0;
4326     mdi_client = CreateWindowA("MDI_client_class",
4327                                  NULL,
4328                                  WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
4329                                  0, 0, 660, 430,
4330                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
4331     ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
4332 
4333     ShowWindow(mdi_client, SW_HIDE);
4334     ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
4335 
4336     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4337                                 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
4338                                 0, 0, 650, 440,
4339                                 mdi_client, 0, GetModuleHandleA(0), NULL);
4340     ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
4341 
4342     SendMessageA(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
4343     ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
4344     zoomed = IsZoomed(mdi_child);
4345     ok(zoomed, "wrong zoomed state %d\n", zoomed);
4346 
4347     ShowWindow(mdi_client, SW_SHOW);
4348     ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
4349 
4350     DestroyWindow(mdi_child);
4351     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
4352 
4353     /* end of test for maximization of MDI child with invisible parent */
4354 
4355     DestroyWindow(mdi_client);
4356     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
4357 
4358     DestroyWindow(mdi_frame);
4359     ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
4360 }
4361 /************************* End of MDI test **********************************/
4362 
4363 static void test_WM_SETREDRAW(HWND hwnd)
4364 {
4365     DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
4366 
4367     flush_events();
4368     flush_sequence();
4369 
4370     SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
4371     ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
4372 
4373     ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
4374     ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
4375 
4376     flush_sequence();
4377     SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
4378     ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
4379 
4380     ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4381     ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
4382 
4383     /* restore original WS_VISIBLE state */
4384     SetWindowLongA(hwnd, GWL_STYLE, style);
4385 
4386     flush_events();
4387     flush_sequence();
4388 }
4389 
4390 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4391 {
4392     struct recvd_message msg;
4393 
4394     if (ignore_message( message )) return 0;
4395 
4396     switch (message)
4397     {
4398 	/* ignore */
4399 	case WM_MOUSEMOVE:
4400 	case WM_NCMOUSEMOVE:
4401 	case WM_NCMOUSELEAVE:
4402 	case WM_SETCURSOR:
4403             return 0;
4404         case WM_NCHITTEST:
4405             return HTCLIENT;
4406     }
4407 
4408     msg.hwnd = hwnd;
4409     msg.message = message;
4410     msg.flags = sent|wparam|lparam;
4411     msg.wParam = wParam;
4412     msg.lParam = lParam;
4413     msg.descr = "dialog";
4414     add_message(&msg);
4415 
4416     if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
4417     if (message == WM_TIMER) EndDialog( hwnd, 0 );
4418     return 0;
4419 }
4420 
4421 static INT_PTR CALLBACK TestModalDlgProc2(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4422 {
4423     struct recvd_message msg;
4424 
4425     if (ignore_message( message )) return 0;
4426 
4427     switch (message)
4428     {
4429 	/* ignore */
4430 	case WM_MOUSEMOVE:
4431 	case WM_NCMOUSEMOVE:
4432 	case WM_NCMOUSELEAVE:
4433 	case WM_SETCURSOR:
4434             return 0;
4435         case WM_NCHITTEST:
4436             return HTCLIENT;
4437     }
4438 
4439     msg.hwnd = hwnd;
4440     msg.message = message;
4441     msg.flags = sent|wparam|lparam;
4442     msg.wParam = wParam;
4443     msg.lParam = lParam;
4444     msg.descr = "dialog";
4445     add_message(&msg);
4446 
4447     if (message == WM_INITDIALOG) EndDialog( hwnd, 0 );
4448     return 0;
4449 }
4450 
4451 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4452 {
4453     DWORD style, exstyle;
4454     INT xmin, xmax;
4455     BOOL ret;
4456 
4457     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4458     style = GetWindowLongA(hwnd, GWL_STYLE);
4459     /* do not be confused by WS_DLGFRAME set */
4460     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4461 
4462     if (clear) ok(style & clear, "style %08x should be set\n", clear);
4463     if (set) ok(!(style & set), "style %08x should not be set\n", set);
4464 
4465     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4466     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
4467     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4468         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
4469     else
4470         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
4471 
4472     style = GetWindowLongA(hwnd, GWL_STYLE);
4473     if (set) ok(style & set, "style %08x should be set\n", set);
4474     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4475 
4476     /* a subsequent call should do nothing */
4477     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4478     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
4479     ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4480 
4481     xmin = 0xdeadbeef;
4482     xmax = 0xdeadbeef;
4483     ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
4484     ok( ret, "GetScrollRange(%d) error %d\n", ctl, GetLastError());
4485     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4486     ok(xmin == min, "unexpected min scroll value %d\n", xmin);
4487     ok(xmax == max, "unexpected max scroll value %d\n", xmax);
4488 }
4489 
4490 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4491 {
4492     DWORD style, exstyle;
4493     SCROLLINFO si;
4494     BOOL ret;
4495 
4496     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4497     style = GetWindowLongA(hwnd, GWL_STYLE);
4498     /* do not be confused by WS_DLGFRAME set */
4499     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4500 
4501     if (clear) ok(style & clear, "style %08x should be set\n", clear);
4502     if (set) ok(!(style & set), "style %08x should not be set\n", set);
4503 
4504     si.cbSize = sizeof(si);
4505     si.fMask = SIF_RANGE;
4506     si.nMin = min;
4507     si.nMax = max;
4508     SetScrollInfo(hwnd, ctl, &si, TRUE);
4509     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4510         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
4511     else
4512         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
4513 
4514     style = GetWindowLongA(hwnd, GWL_STYLE);
4515     if (set) ok(style & set, "style %08x should be set\n", set);
4516     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4517 
4518     /* a subsequent call should do nothing */
4519     SetScrollInfo(hwnd, ctl, &si, TRUE);
4520     if (style & WS_HSCROLL)
4521         ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4522     else if (style & WS_VSCROLL)
4523         ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4524     else
4525         ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4526 
4527     si.fMask = SIF_PAGE;
4528     si.nPage = 5;
4529     SetScrollInfo(hwnd, ctl, &si, FALSE);
4530     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4531 
4532     si.fMask = SIF_POS;
4533     si.nPos = max - 1;
4534     SetScrollInfo(hwnd, ctl, &si, FALSE);
4535     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4536 
4537     si.fMask = SIF_RANGE;
4538     si.nMin = 0xdeadbeef;
4539     si.nMax = 0xdeadbeef;
4540     ret = GetScrollInfo(hwnd, ctl, &si);
4541     ok( ret, "GetScrollInfo error %d\n", GetLastError());
4542     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4543     ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
4544     ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
4545 }
4546 
4547 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
4548 static void test_scroll_messages(HWND hwnd)
4549 {
4550     SCROLLINFO si;
4551     INT min, max;
4552     BOOL ret;
4553 
4554     flush_events();
4555     flush_sequence();
4556 
4557     min = 0xdeadbeef;
4558     max = 0xdeadbeef;
4559     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4560     ok( ret, "GetScrollRange error %d\n", GetLastError());
4561     if (sequence->message != WmGetScrollRangeSeq[0].message)
4562         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4563     /* values of min and max are undefined */
4564     flush_sequence();
4565 
4566     ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
4567     ok( ret, "SetScrollRange error %d\n", GetLastError());
4568     if (sequence->message != WmSetScrollRangeSeq[0].message)
4569         trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4570     flush_sequence();
4571 
4572     min = 0xdeadbeef;
4573     max = 0xdeadbeef;
4574     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4575     ok( ret, "GetScrollRange error %d\n", GetLastError());
4576     if (sequence->message != WmGetScrollRangeSeq[0].message)
4577         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4578     /* values of min and max are undefined */
4579     flush_sequence();
4580 
4581     si.cbSize = sizeof(si);
4582     si.fMask = SIF_RANGE;
4583     si.nMin = 20;
4584     si.nMax = 160;
4585     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4586     if (sequence->message != WmSetScrollRangeSeq[0].message)
4587         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4588     flush_sequence();
4589 
4590     si.fMask = SIF_PAGE;
4591     si.nPage = 10;
4592     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4593     if (sequence->message != WmSetScrollRangeSeq[0].message)
4594         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4595     flush_sequence();
4596 
4597     si.fMask = SIF_POS;
4598     si.nPos = 20;
4599     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4600     if (sequence->message != WmSetScrollRangeSeq[0].message)
4601         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4602     flush_sequence();
4603 
4604     si.fMask = SIF_RANGE;
4605     si.nMin = 0xdeadbeef;
4606     si.nMax = 0xdeadbeef;
4607     ret = GetScrollInfo(hwnd, SB_CTL, &si);
4608     ok( ret, "GetScrollInfo error %d\n", GetLastError());
4609     if (sequence->message != WmGetScrollInfoSeq[0].message)
4610         trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4611     /* values of min and max are undefined */
4612     flush_sequence();
4613 
4614     /* set WS_HSCROLL */
4615     test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4616     /* clear WS_HSCROLL */
4617     test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4618 
4619     /* set WS_HSCROLL */
4620     test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4621     /* clear WS_HSCROLL */
4622     test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4623 
4624     /* set WS_VSCROLL */
4625     test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4626     /* clear WS_VSCROLL */
4627     test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4628 
4629     /* set WS_VSCROLL */
4630     test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4631     /* clear WS_VSCROLL */
4632     test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4633 }
4634 
4635 static void test_showwindow(void)
4636 {
4637     HWND hwnd, hchild;
4638     RECT rc;
4639 
4640     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4641                            100, 100, 200, 200, 0, 0, 0, NULL);
4642     ok (hwnd != 0, "Failed to create overlapped window\n");
4643     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4644                              0, 0, 10, 10, hwnd, 0, 0, NULL);
4645     ok (hchild != 0, "Failed to create child\n");
4646     flush_sequence();
4647 
4648     /* ShowWindow( SW_SHOWNA) for invisible top level window */
4649     trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
4650     ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4651     ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", FALSE);
4652 
4653     /* ShowWindow( SW_SHOWNA) for now visible top level window */
4654     trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
4655     ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4656     ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
4657     /* back to invisible */
4658     ShowWindow(hchild, SW_HIDE);
4659     ShowWindow(hwnd, SW_HIDE);
4660     flush_sequence();
4661     /* ShowWindow(SW_SHOWNA) with child and parent invisible */
4662     trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
4663     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4664     ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
4665     /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */
4666     ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
4667     flush_sequence();
4668     trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
4669     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4670     ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
4671     /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
4672     ShowWindow( hwnd, SW_SHOW);
4673     flush_sequence();
4674     trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
4675     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4676     ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
4677 
4678     /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
4679     ShowWindow( hchild, SW_HIDE);
4680     flush_sequence();
4681     trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
4682     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4683     ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
4684 
4685     SetCapture(hchild);
4686     ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
4687     DestroyWindow(hchild);
4688     ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
4689 
4690     DestroyWindow(hwnd);
4691     flush_sequence();
4692 
4693     /* Popup windows */
4694     /* Test 1:
4695      * 1. Create invisible maximized popup window.
4696      * 2. Move and resize it.
4697      * 3. Show it maximized.
4698      */
4699     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4700     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4701                            100, 100, 200, 200, 0, 0, 0, NULL);
4702     ok (hwnd != 0, "Failed to create popup window\n");
4703     ok(IsZoomed(hwnd), "window should be maximized\n");
4704     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4705 
4706     GetWindowRect(hwnd, &rc);
4707     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4708         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4709         "Invalid maximized size before ShowWindow %s\n", wine_dbgstr_rect( &rc ));
4710     /* Reset window's size & position */
4711     SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
4712     ok(IsZoomed(hwnd), "window should be maximized\n");
4713     flush_sequence();
4714 
4715     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4716     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4717     ok(IsZoomed(hwnd), "window should be maximized\n");
4718     ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
4719 
4720     GetWindowRect(hwnd, &rc);
4721     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4722         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4723         "Invalid maximized size after ShowWindow %s\n", wine_dbgstr_rect( &rc ));
4724     DestroyWindow(hwnd);
4725     flush_sequence();
4726 
4727     /* Test 2:
4728      * 1. Create invisible maximized popup window.
4729      * 2. 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     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4739     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4740     ok(IsZoomed(hwnd), "window should be maximized\n");
4741     ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
4742     DestroyWindow(hwnd);
4743     flush_sequence();
4744 
4745     /* Test 3:
4746      * 1. Create visible maximized popup window.
4747      */
4748     trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
4749     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
4750                            100, 100, 200, 200, 0, 0, 0, NULL);
4751     ok (hwnd != 0, "Failed to create popup window\n");
4752     ok(IsZoomed(hwnd), "window should be maximized\n");
4753     ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4754     DestroyWindow(hwnd);
4755     flush_sequence();
4756 
4757     /* Test 4:
4758      * 1. Create visible popup window.
4759      * 2. Maximize it.
4760      */
4761     trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
4762     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
4763                            100, 100, 200, 200, 0, 0, 0, NULL);
4764     ok (hwnd != 0, "Failed to create popup window\n");
4765     ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
4766     ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE);
4767 
4768     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
4769     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4770     ok(IsZoomed(hwnd), "window should be maximized\n");
4771     ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
4772     DestroyWindow(hwnd);
4773     flush_sequence();
4774 }
4775 
4776 static void test_recursive_activation(void)
4777 {
4778     static const struct message seq[] =
4779     {
4780         { HCBT_ACTIVATE, hook },
4781         { WM_NCACTIVATE, sent|wparam, TRUE },
4782         { WM_ACTIVATE, sent|wparam, WA_ACTIVE },
4783         { HCBT_ACTIVATE, hook },
4784         { WM_NCACTIVATE, sent|wparam, FALSE },
4785         { WM_ACTIVATE, sent|wparam, WA_INACTIVE },
4786         { WM_SETFOCUS, sent|optional },
4787         { 0 }
4788     };
4789     HWND hwnd, recursive;
4790 
4791     hwnd = CreateWindowExA(0, "SimpleWindowClass", NULL, WS_OVERLAPPED|WS_VISIBLE,
4792                               100, 100, 200, 200, 0, 0, 0, NULL);
4793     ok(hwnd != 0, "Failed to create simple window\n");
4794 
4795     recursive = CreateWindowExA(0, "RecursiveActivationClass", NULL, WS_OVERLAPPED|WS_VISIBLE,
4796                                 10, 10, 50, 50, hwnd, 0, 0, NULL);
4797     ok(recursive != 0, "Failed to create recursive activation window\n");
4798     SetActiveWindow(hwnd);
4799 
4800     flush_sequence();
4801     SetActiveWindow(recursive);
4802     ok_sequence(seq, "Recursive Activation", FALSE);
4803 
4804     DestroyWindow(recursive);
4805     DestroyWindow(hwnd);
4806     flush_sequence();
4807 }
4808 
4809 static void test_sys_menu(void)
4810 {
4811     HWND hwnd;
4812     HMENU hmenu;
4813     UINT state;
4814 
4815     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4816                            100, 100, 200, 200, 0, 0, 0, NULL);
4817     ok (hwnd != 0, "Failed to create overlapped window\n");
4818 
4819     flush_sequence();
4820 
4821     /* test existing window without CS_NOCLOSE style */
4822     hmenu = GetSystemMenu(hwnd, FALSE);
4823     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4824 
4825     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4826     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4827     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4828 
4829     EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
4830     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4831 
4832     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4833     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4834     ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
4835 
4836     EnableMenuItem(hmenu, SC_CLOSE, 0);
4837     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4838 
4839     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4840     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4841     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4842 
4843     /* test whether removing WS_SYSMENU destroys a system menu */
4844     SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
4845     SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4846     flush_sequence();
4847     hmenu = GetSystemMenu(hwnd, FALSE);
4848     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4849 
4850     DestroyWindow(hwnd);
4851 
4852     /* test new window with CS_NOCLOSE style */
4853     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4854                            100, 100, 200, 200, 0, 0, 0, NULL);
4855     ok (hwnd != 0, "Failed to create overlapped window\n");
4856 
4857     hmenu = GetSystemMenu(hwnd, FALSE);
4858     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4859 
4860     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4861     ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4862 
4863     DestroyWindow(hwnd);
4864 
4865     /* test new window without WS_SYSMENU style */
4866     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
4867                            100, 100, 200, 200, 0, 0, 0, NULL);
4868     ok(hwnd != 0, "Failed to create overlapped window\n");
4869 
4870     hmenu = GetSystemMenu(hwnd, FALSE);
4871     ok(!hmenu, "GetSystemMenu error %d\n", GetLastError());
4872 
4873     DestroyWindow(hwnd);
4874 }
4875 
4876 /* For shown WS_OVERLAPPEDWINDOW */
4877 static const struct message WmSetIcon_1[] = {
4878     { WM_SETICON, sent },
4879     { 0x00AE, sent|defwinproc|optional }, /* XP */
4880     { WM_GETTEXT, sent|defwinproc|optional },
4881     { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
4882     { 0 }
4883 };
4884 
4885 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
4886 static const struct message WmSetIcon_2[] = {
4887     { WM_SETICON, sent },
4888     { 0 }
4889 };
4890 
4891 /* Sending undocumented 0x3B message with wparam = 0x8000000b */
4892 static const struct message WmInitEndSession[] = {
4893     { 0x003B, sent },
4894     { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4895     { 0 }
4896 };
4897 
4898 /* Sending undocumented 0x3B message with wparam = 0x0000000b */
4899 static const struct message WmInitEndSession_2[] = {
4900     { 0x003B, sent },
4901     { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4902     { 0 }
4903 };
4904 
4905 /* Sending undocumented 0x3B message with wparam = 0x80000008 */
4906 static const struct message WmInitEndSession_3[] = {
4907     { 0x003B, sent },
4908     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4909     { 0 }
4910 };
4911 
4912 /* Sending undocumented 0x3B message with wparam = 0x00000008 */
4913 static const struct message WmInitEndSession_4[] = {
4914     { 0x003B, sent },
4915     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4916     { 0 }
4917 };
4918 
4919 /* Sending undocumented 0x3B message with wparam = 0x80000001 */
4920 static const struct message WmInitEndSession_5[] = {
4921     { 0x003B, sent },
4922     { WM_ENDSESSION, sent|defwinproc/*|wparam*/|lparam, 1, ENDSESSION_LOGOFF },
4923     { 0 }
4924 };
4925 
4926 static const struct message WmOptionalPaint[] = {
4927     { WM_PAINT, sent|optional },
4928     { WM_NCPAINT, sent|beginpaint|optional },
4929     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4930     { WM_ERASEBKGND, sent|beginpaint|optional },
4931     { 0 }
4932 };
4933 
4934 static const struct message WmZOrder[] = {
4935     { WM_WINDOWPOSCHANGING, sent|wparam, 0, 0 },
4936     { WM_GETMINMAXINFO, sent|defwinproc|wparam, 0, 0 },
4937     { HCBT_ACTIVATE, hook },
4938     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
4939     { WM_WINDOWPOSCHANGING, sent|wparam, 3, 0 },
4940     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0 },
4941     { WM_GETTEXT, sent|optional },
4942     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
4943     { WM_ACTIVATEAPP, sent|wparam, 1, 0 },
4944     { WM_NCACTIVATE, sent|lparam, 1, 0 },
4945     { WM_GETTEXT, sent|defwinproc|optional },
4946     { WM_GETTEXT, sent|defwinproc|optional },
4947     { WM_ACTIVATE, sent|wparam|lparam, 1, 0 },
4948     { HCBT_SETFOCUS, hook },
4949     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
4950     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4951     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
4952     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
4953     { WM_GETTEXT, sent|optional },
4954     { WM_NCCALCSIZE, sent|optional },
4955     { 0 }
4956 };
4957 
4958 static void CALLBACK apc_test_proc(ULONG_PTR param)
4959 {
4960     /* nothing */
4961 }
4962 
4963 static void test_MsgWaitForMultipleObjects(HWND hwnd)
4964 {
4965     DWORD ret;
4966     MSG msg;
4967 
4968     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4969     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4970 
4971     PostMessageA(hwnd, WM_USER, 0, 0);
4972 
4973     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4974     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4975 
4976     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4977     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
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_NOREMOVE ), "PeekMessage should succeed\n");
4988     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4989 
4990     /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
4991     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4992     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4993 
4994     PostMessageA(hwnd, WM_USER, 0, 0);
4995 
4996     /* new incoming message causes it to become signaled again */
4997     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4998     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4999 
5000     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5001     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5002     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5003     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5004 
5005     /* MWMO_INPUTAVAILABLE should succeed even if the message was already seen */
5006     PostMessageA( hwnd, WM_USER, 0, 0 );
5007     ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
5008     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5009 
5010     ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_INPUTAVAILABLE );
5011     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5012 
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     /* without MWMO_ALERTABLE the result is never WAIT_IO_COMPLETION */
5017     ret = QueueUserAPC( apc_test_proc, GetCurrentThread(), 0 );
5018     ok(ret, "QueueUserAPC failed %u\n", GetLastError());
5019 
5020     ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, 0 );
5021     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5022 
5023     /* but even with MWMO_ALERTABLE window events are preferred */
5024     PostMessageA( hwnd, WM_USER, 0, 0 );
5025 
5026     ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_ALERTABLE );
5027     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5028 
5029     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5030     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5031 
5032     /* the APC call is still queued */
5033     ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_ALERTABLE );
5034     ok(ret == WAIT_IO_COMPLETION, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5035 }
5036 
5037 static void test_WM_DEVICECHANGE(HWND hwnd)
5038 {
5039     DWORD ret;
5040     MSG msg;
5041     int i;
5042     static const WPARAM wparams[] = {0,
5043                                      DBT_DEVNODES_CHANGED,
5044                                      DBT_QUERYCHANGECONFIG,
5045                                      DBT_CONFIGCHANGED,
5046                                      DBT_CONFIGCHANGECANCELED,
5047                                      DBT_NO_DISK_SPACE,
5048                                      DBT_LOW_DISK_SPACE,
5049                                      DBT_CONFIGMGPRIVATE, /* 0x7fff */
5050                                      DBT_DEVICEARRIVAL,   /* 0x8000 */
5051                                      DBT_DEVICEQUERYREMOVE,
5052                                      DBT_DEVICEQUERYREMOVEFAILED,
5053                                      DBT_DEVICEREMOVEPENDING,
5054                                      DBT_DEVICEREMOVECOMPLETE,
5055                                      DBT_DEVICETYPESPECIFIC,
5056                                      DBT_CUSTOMEVENT};
5057 
5058     for (i = 0; i < ARRAY_SIZE(wparams); i++)
5059     {
5060         SetLastError(0xdeadbeef);
5061         ret = PostMessageA(hwnd, WM_DEVICECHANGE, wparams[i], 0);
5062         if (wparams[i] & 0x8000)
5063         {
5064             ok(ret == FALSE, "PostMessage should returned %d\n", ret);
5065             ok(GetLastError() == ERROR_MESSAGE_SYNC_ONLY, "PostMessage error %08x\n", GetLastError());
5066         }
5067         else
5068         {
5069             ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5070             ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
5071             memset(&msg, 0, sizeof(msg));
5072             ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should succeed\n");
5073             ok(msg.message == WM_DEVICECHANGE, "got %04x instead of WM_DEVICECHANGE\n", msg.message);
5074         }
5075     }
5076 }
5077 
5078 static DWORD CALLBACK show_window_thread(LPVOID arg)
5079 {
5080    HWND hwnd = arg;
5081 
5082    /* function will not return if ShowWindow(SW_HIDE) calls SendMessage() */
5083    ok(ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow(SW_HIDE) expected FALSE\n");
5084 
5085    return 0;
5086 }
5087 
5088 /* Helper function to easier test SetWindowPos messages */
5089 #define test_msg_setpos( expected_list, flags, todo ) \
5090         test_msg_setpos_( (expected_list), (flags), (todo), __FILE__, __LINE__)
5091 static void test_msg_setpos_(const struct message *expected_list, UINT flags, BOOL todo, const char *file, int line)
5092 {
5093     HWND hwnd;
5094 
5095     flush_events();
5096     flush_sequence();
5097     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5098                              10, 10, 100, 100, NULL, 0, 0, NULL );
5099     ok (hwnd != 0, "Failed to create popup window\n");
5100     SetWindowPos(hwnd, NULL, 0, 0, 100, 100, flags);
5101     ok_sequence_(expected_list, "SetWindowPos:show_popup_first_show_window", todo, file, line);
5102     DestroyWindow(hwnd);
5103 }
5104 
5105 /* test if we receive the right sequence of messages */
5106 static void test_messages(void)
5107 {
5108     DWORD tid;
5109     HANDLE hthread;
5110     HWND hwnd, hparent, hchild;
5111     HWND hchild2, hbutton;
5112     HMENU hmenu;
5113     MSG msg;
5114     LRESULT res;
5115     POINT pos;
5116     BOOL ret;
5117 
5118     flush_sequence();
5119 
5120     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5121                            100, 100, 200, 200, 0, 0, 0, NULL);
5122     ok (hwnd != 0, "Failed to create overlapped window\n");
5123     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
5124 
5125     /* test ShowWindow(SW_HIDE) on a newly created invisible window */
5126     ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
5127     ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
5128 
5129     /* test WM_SETREDRAW on a not visible top level window */
5130     test_WM_SETREDRAW(hwnd);
5131 
5132     SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5133     flush_events();
5134     ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
5135     ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
5136 
5137     ok(GetActiveWindow() == hwnd, "window should be active\n");
5138     ok(GetFocus() == hwnd, "window should have input focus\n");
5139     ShowWindow(hwnd, SW_HIDE);
5140     flush_events();
5141     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5142 
5143     /* test ShowWindow(SW_HIDE) on a hidden window - single threaded */
5144     ok(ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow(SW_HIDE) expected FALSE\n");
5145     flush_events();
5146     ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5147 
5148     /* test ShowWindow(SW_HIDE) on a hidden window -  multi-threaded */
5149     hthread = CreateThread(NULL, 0, show_window_thread, hwnd, 0, &tid);
5150     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
5151     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5152     CloseHandle(hthread);
5153     flush_events();
5154     ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5155 
5156     ShowWindow(hwnd, SW_SHOW);
5157     flush_events();
5158     ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
5159 
5160     ShowWindow(hwnd, SW_HIDE);
5161     flush_events();
5162     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5163 
5164     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5165     flush_events();
5166     ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
5167     flush_sequence();
5168 
5169     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZE)
5170     {
5171         ShowWindow(hwnd, SW_RESTORE);
5172         flush_events();
5173         ok_sequence(WmShowRestoreMaxOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
5174         flush_sequence();
5175     }
5176 
5177     ShowWindow(hwnd, SW_MINIMIZE);
5178     flush_events();
5179     ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", FALSE);
5180     flush_sequence();
5181 
5182     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE)
5183     {
5184         ShowWindow(hwnd, SW_RESTORE);
5185         flush_events();
5186         ok_sequence(WmShowRestoreMinOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
5187         flush_sequence();
5188     }
5189 
5190     ShowWindow(hwnd, SW_SHOW);
5191     flush_events();
5192     ok_sequence(WmOptionalPaint, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
5193 
5194     SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5195     ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
5196     ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
5197     ok(GetActiveWindow() == hwnd, "window should still be active\n");
5198 
5199     /* test WM_SETREDRAW on a visible top level window */
5200     ShowWindow(hwnd, SW_SHOW);
5201     flush_events();
5202     test_WM_SETREDRAW(hwnd);
5203 
5204     trace("testing scroll APIs on a visible top level window %p\n", hwnd);
5205     test_scroll_messages(hwnd);
5206 
5207     /* test resizing and moving */
5208     SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
5209     ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
5210     flush_events();
5211     flush_sequence();
5212     SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
5213     ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
5214     flush_events();
5215     flush_sequence();
5216     SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER|SWP_NOACTIVATE );
5217     ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
5218     flush_events();
5219     flush_sequence();
5220 
5221     /* popups don't get WM_GETMINMAXINFO */
5222     SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
5223     SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
5224     flush_sequence();
5225     SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
5226     ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
5227 
5228     DestroyWindow(hwnd);
5229     ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
5230 
5231     /* Test if windows are correctly drawn when first shown */
5232 
5233     /* Visible, redraw */
5234     flush_events();
5235     flush_sequence();
5236     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5237                              10, 10, 100, 100, NULL, 0, 0, NULL );
5238     ok (hwnd != 0, "Failed to create popup window\n");
5239     RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
5240     ok_sequence(WmShowPopupFirstDrawSeq_1, "RedrawWindow:show_popup_first_draw_visible", FALSE);
5241     DestroyWindow(hwnd);
5242 
5243     /* Invisible, show, message */
5244     flush_events();
5245     flush_sequence();
5246     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5247                              10, 10, 100, 100, NULL, 0, 0, NULL );
5248     ok (hwnd != 0, "Failed to create popup window\n");
5249     ShowWindow(hwnd, SW_SHOW);
5250     SendMessageW(hwnd, WM_PAINT, 0, 0);
5251     ok_sequence(WmShowPopupFirstDrawSeq_1, "RedrawWindow:show_popup_first_draw_show", FALSE);
5252     DestroyWindow(hwnd);
5253 
5254     /* Invisible, show maximized, redraw */
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_SHOWMAXIMIZED);
5261     RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
5262     ok_sequence(WmShowPopupFirstDrawSeq_2, "RedrawWindow:show_popup_first_draw_show_maximized", FALSE);
5263     DestroyWindow(hwnd);
5264 
5265     /* Test SetWindowPos */
5266     test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW, FALSE);
5267     test_msg_setpos(WmFirstDrawSetWindowPosSeq2, 0, FALSE);
5268     test_msg_setpos(WmFirstDrawSetWindowPosSeq3,
5269             SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER, FALSE);
5270 
5271     test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOSIZE, FALSE);
5272     test_msg_setpos(WmFirstDrawSetWindowPosSeq4, SWP_SHOWWINDOW | SWP_NOMOVE, FALSE);
5273     test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCLIENTSIZE, FALSE);
5274     test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCLIENTMOVE, FALSE);
5275     test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOZORDER, FALSE);
5276 
5277     test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE, FALSE);
5278     test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOCLIENTMOVE, FALSE);
5279     test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOCLIENTSIZE, FALSE);
5280     test_msg_setpos(WmFirstDrawSetWindowPosSeq5, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOMOVE, FALSE);
5281     test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOSIZE, FALSE);
5282     test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOZORDER, FALSE);
5283 
5284     test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS, FALSE);
5285     test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOCLIENTMOVE, FALSE);
5286     test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOCLIENTSIZE, FALSE);
5287     test_msg_setpos(WmFirstDrawSetWindowPosSeq4, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOMOVE, FALSE);
5288     test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOSIZE, FALSE);
5289     test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOZORDER, FALSE);
5290 
5291     test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW, FALSE);
5292     test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOCLIENTMOVE, FALSE);
5293     test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOCLIENTSIZE, FALSE);
5294     test_msg_setpos(WmFirstDrawSetWindowPosSeq5, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOMOVE, FALSE);
5295     test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOSIZE, FALSE);
5296     test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOZORDER, FALSE);
5297 
5298     /* Test SetWindowPos with child windows */
5299     flush_events();
5300     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5301                               100, 100, 200, 200, 0, 0, 0, NULL);
5302     ok (hparent != 0, "Failed to create parent window\n");
5303 
5304     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5305                              0, 0, 10, 10, hparent, 0, 0, NULL);
5306     ok (hchild != 0, "Failed to create child window\n");
5307     flush_sequence();
5308     SetWindowPos(hparent, NULL, 0, 0, 100, 100, SWP_SHOWWINDOW);
5309     ok_sequence(WmFirstDrawChildSeq1, /* Expect no messages for the child */
5310                 "SetWindowPos:show_popup_first_show_window_child1", FALSE);
5311     DestroyWindow(hchild);
5312     DestroyWindow(hparent);
5313 
5314     flush_events();
5315     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN,
5316                               100, 100, 200, 200, 0, 0, 0, NULL);
5317     ok (hparent != 0, "Failed to create parent window\n");
5318 
5319     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5320                              0, 0, 10, 10, hparent, 0, 0, NULL);
5321     ok (hchild != 0, "Failed to create child window\n");
5322     flush_sequence();
5323     SetWindowPos(hparent, NULL, 0, 0, 100, 100, SWP_SHOWWINDOW);
5324     ok_sequence(WmFirstDrawChildSeq2, /* Expect child to be redrawn */
5325                 "SetWindowPos:show_popup_first_show_window_child2", FALSE);
5326     DestroyWindow(hchild);
5327     DestroyWindow(hparent);
5328 
5329     /* Test message sequence for extreme position and size */
5330 
5331     flush_sequence();
5332     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5333                              -10, -10, 10000, 10000, NULL, 0, 0, NULL );
5334     ok (hwnd != 0, "Failed to create popup window\n");
5335     ok_sequence(WmShowPopupExtremeLocationSeq, "RedrawWindow:show_popup_extreme_location", FALSE);
5336     DestroyWindow(hwnd);
5337 
5338 
5339     /* Test child windows */
5340 
5341     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5342                               100, 100, 200, 200, 0, 0, 0, NULL);
5343     ok (hparent != 0, "Failed to create parent window\n");
5344     flush_sequence();
5345 
5346     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
5347                              0, 0, 10, 10, hparent, 0, 0, NULL);
5348     ok (hchild != 0, "Failed to create child window\n");
5349     ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
5350     DestroyWindow(hchild);
5351     flush_sequence();
5352 
5353     /* visible child window with a caption */
5354     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
5355                              WS_CHILD | WS_VISIBLE | WS_CAPTION,
5356                              0, 0, 10, 10, hparent, 0, 0, NULL);
5357     ok (hchild != 0, "Failed to create child window\n");
5358     ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
5359 
5360     trace("testing scroll APIs on a visible child window %p\n", hchild);
5361     test_scroll_messages(hchild);
5362 
5363     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5364     ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
5365 
5366     DestroyWindow(hchild);
5367     flush_sequence();
5368 
5369     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5370                              0, 0, 10, 10, hparent, 0, 0, NULL);
5371     ok (hchild != 0, "Failed to create child window\n");
5372     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
5373 
5374     hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
5375                                100, 100, 50, 50, hparent, 0, 0, NULL);
5376     ok (hchild2 != 0, "Failed to create child2 window\n");
5377     flush_sequence();
5378 
5379     hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
5380                               0, 100, 50, 50, hchild, 0, 0, NULL);
5381     ok (hbutton != 0, "Failed to create button window\n");
5382 
5383     /* test WM_SETREDRAW on a not visible child window */
5384     test_WM_SETREDRAW(hchild);
5385 
5386     ShowWindow(hchild, SW_SHOW);
5387     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5388 
5389     /* check parent messages too */
5390     log_all_parent_messages++;
5391     ShowWindow(hchild, SW_HIDE);
5392     ok_sequence(WmHideChildSeq2, "ShowWindow(SW_HIDE):child", FALSE);
5393     log_all_parent_messages--;
5394 
5395     ShowWindow(hchild, SW_SHOW);
5396     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5397 
5398     ShowWindow(hchild, SW_HIDE);
5399     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
5400 
5401     ShowWindow(hchild, SW_SHOW);
5402     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5403 
5404     /* test WM_SETREDRAW on a visible child window */
5405     test_WM_SETREDRAW(hchild);
5406 
5407     log_all_parent_messages++;
5408     MoveWindow(hchild, 10, 10, 20, 20, TRUE);
5409     ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
5410     log_all_parent_messages--;
5411 
5412     ShowWindow(hchild, SW_HIDE);
5413     flush_sequence();
5414     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5415     ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
5416 
5417     ShowWindow(hchild, SW_HIDE);
5418     flush_sequence();
5419     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
5420     ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
5421 
5422     /* DestroyWindow sequence below expects that a child has focus */
5423     SetFocus(hchild);
5424     flush_sequence();
5425 
5426     DestroyWindow(hchild);
5427     ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
5428     DestroyWindow(hchild2);
5429     DestroyWindow(hbutton);
5430 
5431     flush_sequence();
5432     hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
5433                              0, 0, 100, 100, hparent, 0, 0, NULL);
5434     ok (hchild != 0, "Failed to create child popup window\n");
5435     ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
5436     DestroyWindow(hchild);
5437 
5438     /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
5439     flush_sequence();
5440     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
5441                              0, 0, 100, 100, hparent, 0, 0, NULL);
5442     ok (hchild != 0, "Failed to create popup window\n");
5443     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
5444     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5445     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
5446     flush_sequence();
5447     ShowWindow(hchild, SW_SHOW);
5448     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
5449     flush_sequence();
5450     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5451     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
5452     flush_sequence();
5453     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5454     ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
5455     DestroyWindow(hchild);
5456 
5457     /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
5458      * changes nothing in message sequences.
5459      */
5460     flush_sequence();
5461     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5462                              0, 0, 100, 100, hparent, 0, 0, NULL);
5463     ok (hchild != 0, "Failed to create popup window\n");
5464     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
5465     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5466     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
5467     flush_sequence();
5468     ShowWindow(hchild, SW_SHOW);
5469     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
5470     flush_sequence();
5471     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5472     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
5473     DestroyWindow(hchild);
5474 
5475     flush_sequence();
5476     hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
5477                            0, 0, 100, 100, hparent, 0, 0, NULL);
5478     ok(hwnd != 0, "Failed to create custom dialog window\n");
5479     ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
5480 
5481     if(0) {
5482     trace("testing scroll APIs on a visible dialog %p\n", hwnd);
5483     test_scroll_messages(hwnd);
5484     }
5485 
5486     flush_sequence();
5487 
5488     test_def_id = TRUE;
5489     SendMessageA(hwnd, WM_NULL, 0, 0);
5490 
5491     flush_sequence();
5492     after_end_dialog = TRUE;
5493     EndDialog( hwnd, 0 );
5494     ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
5495 
5496     DestroyWindow(hwnd);
5497     after_end_dialog = FALSE;
5498     test_def_id = FALSE;
5499 
5500     ok(GetCursorPos(&pos), "GetCursorPos failed\n");
5501     ok(SetCursorPos(109, 109), "SetCursorPos failed\n");
5502 
5503     hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP|WS_CHILD,
5504                            0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
5505     ok(hwnd != 0, "Failed to create custom dialog window\n");
5506     flush_sequence();
5507     trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
5508     ShowWindow(hwnd, SW_SHOW);
5509     ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
5510 
5511     flush_events();
5512     flush_sequence();
5513     ret = DrawMenuBar(hwnd);
5514     ok(ret, "DrawMenuBar failed: %d\n", GetLastError());
5515     flush_events();
5516     ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
5517     ok(SetCursorPos(pos.x, pos.y), "SetCursorPos failed\n");
5518 
5519     DestroyWindow(hwnd);
5520 
5521     hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_CHILD|WS_VISIBLE,
5522             0, 0, 100, 100, hparent, 0, GetModuleHandleA(0), NULL);
5523     ok(hwnd != 0, "Failed to create custom dialog window\n");
5524     flush_events();
5525     flush_sequence();
5526     ret = DrawMenuBar(hwnd);
5527     ok(ret, "DrawMenuBar failed: %d\n", GetLastError());
5528     flush_events();
5529     ok_sequence(WmEmptySeq, "DrawMenuBar for a child window", FALSE);
5530 
5531     DestroyWindow(hwnd);
5532 
5533     flush_sequence();
5534     DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
5535     ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
5536 
5537     DestroyWindow(hparent);
5538     flush_sequence();
5539 
5540     /* Message sequence for SetMenu */
5541     ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a destroyed window\n");
5542     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "last error is %d\n", GetLastError());
5543     ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
5544 
5545     hmenu = CreateMenu();
5546     ok (hmenu != 0, "Failed to create menu\n");
5547     ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
5548     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5549                            100, 100, 200, 200, 0, hmenu, 0, NULL);
5550     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
5551     ok (SetMenu(hwnd, 0), "SetMenu\n");
5552     ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
5553     ok (SetMenu(hwnd, 0), "SetMenu\n");
5554     ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
5555     ShowWindow(hwnd, SW_SHOW);
5556     UpdateWindow( hwnd );
5557     flush_events();
5558     flush_sequence();
5559     ok (SetMenu(hwnd, 0), "SetMenu\n");
5560     ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
5561     ok (SetMenu(hwnd, hmenu), "SetMenu\n");
5562     ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
5563 
5564     UpdateWindow( hwnd );
5565     flush_events();
5566     flush_sequence();
5567     ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
5568     flush_events();
5569     ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
5570 
5571     DestroyWindow(hwnd);
5572     flush_sequence();
5573 
5574     /* Message sequence for EnableWindow */
5575     hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5576                               100, 100, 200, 200, 0, 0, 0, NULL);
5577     ok (hparent != 0, "Failed to create parent window\n");
5578     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5579                              0, 0, 10, 10, hparent, 0, 0, NULL);
5580     ok (hchild != 0, "Failed to create child window\n");
5581 
5582     SetFocus(hchild);
5583     flush_events();
5584     flush_sequence();
5585 
5586     EnableWindow(hparent, FALSE);
5587     ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
5588 
5589     EnableWindow(hparent, FALSE);
5590     ok_sequence(WmEnableWindowSeq_2, "EnableWindow(FALSE)", FALSE);
5591 
5592     EnableWindow(hparent, TRUE);
5593     ok_sequence(WmEnableWindowSeq_3, "EnableWindow(TRUE)", FALSE);
5594 
5595     EnableWindow(hparent, TRUE);
5596     ok_sequence(WmEnableWindowSeq_4, "EnableWindow(TRUE)", FALSE);
5597 
5598     flush_events();
5599     flush_sequence();
5600 
5601     test_MsgWaitForMultipleObjects(hparent);
5602     test_WM_DEVICECHANGE(hparent);
5603 
5604     /* the following test causes an exception in user.exe under win9x */
5605     if (!PostMessageW( hparent, WM_USER, 0, 0 ))
5606     {
5607         DestroyWindow(hparent);
5608         flush_sequence();
5609         return;
5610     }
5611     PostMessageW( hparent, WM_USER+1, 0, 0 );
5612     /* PeekMessage(NULL) fails, but still removes the message */
5613     SetLastError(0xdeadbeef);
5614     ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
5615     ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
5616         GetLastError() == 0xdeadbeef, /* NT4 */
5617         "last error is %d\n", GetLastError() );
5618     ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
5619     ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
5620 
5621     DestroyWindow(hchild);
5622     DestroyWindow(hparent);
5623     flush_sequence();
5624 
5625     /* Message sequences for WM_SETICON */
5626     trace("testing WM_SETICON\n");
5627     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
5628                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5629                            NULL, NULL, 0);
5630     ShowWindow(hwnd, SW_SHOW);
5631     UpdateWindow(hwnd);
5632     flush_events();
5633     flush_sequence();
5634     SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5635     ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
5636 
5637     ShowWindow(hwnd, SW_HIDE);
5638     flush_events();
5639     flush_sequence();
5640     SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5641     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window with caption", FALSE);
5642     DestroyWindow(hwnd);
5643     flush_sequence();
5644 
5645     hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
5646                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5647                            NULL, NULL, 0);
5648     ShowWindow(hwnd, SW_SHOW);
5649     UpdateWindow(hwnd);
5650     flush_events();
5651     flush_sequence();
5652     SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5653     ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
5654 
5655     ShowWindow(hwnd, SW_HIDE);
5656     flush_events();
5657     flush_sequence();
5658     SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5659     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
5660 
5661     flush_sequence();
5662     res = SendMessageA(hwnd, 0x3B, 0x8000000b, 0);
5663     if (!res)
5664     {
5665         todo_wine win_skip( "Message 0x3b not supported\n" );
5666         goto done;
5667     }
5668     ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE);
5669     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %ld\n", res);
5670     res = SendMessageA(hwnd, 0x3B, 0x0000000b, 0);
5671     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE);
5672     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %ld\n", res);
5673     res = SendMessageA(hwnd, 0x3B, 0x0000000f, 0);
5674     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE);
5675     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %ld\n", res);
5676 
5677     flush_sequence();
5678     res = SendMessageA(hwnd, 0x3B, 0x80000008, 0);
5679     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE);
5680     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %ld\n", res);
5681     res = SendMessageA(hwnd, 0x3B, 0x00000008, 0);
5682     ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE);
5683     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %ld\n", res);
5684 
5685     res = SendMessageA(hwnd, 0x3B, 0x80000004, 0);
5686     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE);
5687     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %ld\n", res);
5688 
5689     res = SendMessageA(hwnd, 0x3B, 0x80000001, 0);
5690     ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE);
5691     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %ld\n", res);
5692 
5693 done:
5694     DestroyWindow(hwnd);
5695     flush_sequence();
5696 }
5697 
5698 static void test_setwindowpos(void)
5699 {
5700     HWND hwnd;
5701     RECT rc;
5702     LRESULT res;
5703     const INT winX = 100;
5704     const INT winY = 100;
5705     const INT sysX = GetSystemMetrics(SM_CXMINTRACK);
5706 
5707     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
5708                            0, 0, winX, winY, 0,
5709                            NULL, NULL, 0);
5710 
5711     GetWindowRect(hwnd, &rc);
5712     expect(sysX, rc.right);
5713     expect(winY, rc.bottom);
5714 
5715     flush_events();
5716     flush_sequence();
5717     res = SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, winX, winY, 0);
5718     ok_sequence(WmZOrder, "Z-Order", TRUE);
5719     ok(res == TRUE, "SetWindowPos expected TRUE, got %ld\n", res);
5720 
5721     GetWindowRect(hwnd, &rc);
5722     expect(sysX, rc.right);
5723     expect(winY, rc.bottom);
5724     DestroyWindow(hwnd);
5725 }
5726 
5727 static void invisible_parent_tests(void)
5728 {
5729     HWND hparent, hchild;
5730 
5731     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
5732                               100, 100, 200, 200, 0, 0, 0, NULL);
5733     ok (hparent != 0, "Failed to create parent window\n");
5734     flush_sequence();
5735 
5736     /* test showing child with hidden parent */
5737 
5738     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5739                              0, 0, 10, 10, hparent, 0, 0, NULL);
5740     ok (hchild != 0, "Failed to create child window\n");
5741     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
5742 
5743     ShowWindow( hchild, SW_MINIMIZE );
5744     ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
5745     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5746     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5747 
5748     /* repeat */
5749     flush_events();
5750     flush_sequence();
5751     ShowWindow( hchild, SW_MINIMIZE );
5752     ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
5753 
5754     DestroyWindow(hchild);
5755     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5756                              0, 0, 10, 10, hparent, 0, 0, NULL);
5757     flush_sequence();
5758 
5759     ShowWindow( hchild, SW_MAXIMIZE );
5760     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
5761     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5762     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5763 
5764     /* repeat */
5765     flush_events();
5766     flush_sequence();
5767     ShowWindow( hchild, SW_MAXIMIZE );
5768     ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
5769 
5770     DestroyWindow(hchild);
5771     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5772                              0, 0, 10, 10, hparent, 0, 0, NULL);
5773     flush_sequence();
5774 
5775     ShowWindow( hchild, SW_RESTORE );
5776     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
5777     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5778     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5779 
5780     DestroyWindow(hchild);
5781     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5782                              0, 0, 10, 10, hparent, 0, 0, NULL);
5783     flush_sequence();
5784 
5785     ShowWindow( hchild, SW_SHOWMINIMIZED );
5786     ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
5787     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5788     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5789 
5790     /* repeat */
5791     flush_events();
5792     flush_sequence();
5793     ShowWindow( hchild, SW_SHOWMINIMIZED );
5794     ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
5795 
5796     DestroyWindow(hchild);
5797     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5798                              0, 0, 10, 10, hparent, 0, 0, NULL);
5799     flush_sequence();
5800 
5801     /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
5802     ShowWindow( hchild, SW_SHOWMAXIMIZED );
5803     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
5804     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5805     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
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     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5813     ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5814     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5815     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5816 
5817     /* repeat */
5818     flush_events();
5819     flush_sequence();
5820     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5821     ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5822 
5823     DestroyWindow(hchild);
5824     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5825                              0, 0, 10, 10, hparent, 0, 0, NULL);
5826     flush_sequence();
5827 
5828     /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
5829     ShowWindow( hchild, SW_FORCEMINIMIZE );
5830     ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
5831 todo_wine {
5832     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5833 }
5834     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5835 
5836     DestroyWindow(hchild);
5837     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5838                              0, 0, 10, 10, hparent, 0, 0, NULL);
5839     flush_sequence();
5840 
5841     ShowWindow( hchild, SW_SHOWNA );
5842     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5843     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5844     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5845 
5846     /* repeat */
5847     flush_events();
5848     flush_sequence();
5849     ShowWindow( hchild, SW_SHOWNA );
5850     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5851 
5852     DestroyWindow(hchild);
5853     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5854                              0, 0, 10, 10, hparent, 0, 0, NULL);
5855     flush_sequence();
5856 
5857     ShowWindow( hchild, SW_SHOW );
5858     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5859     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5860     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5861 
5862     /* repeat */
5863     flush_events();
5864     flush_sequence();
5865     ShowWindow( hchild, SW_SHOW );
5866     ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5867 
5868     ShowWindow( hchild, SW_HIDE );
5869     ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
5870     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5871     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5872 
5873     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5874     ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
5875     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5876     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5877 
5878     SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5879     ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
5880     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
5881     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5882 
5883     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5884     flush_sequence();
5885     DestroyWindow(hchild);
5886     ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
5887 
5888     DestroyWindow(hparent);
5889     flush_sequence();
5890 }
5891 
5892 /****************** button message test *************************/
5893 #define ID_BUTTON 0x000e
5894 
5895 static const struct message WmSetFocusButtonSeq[] =
5896 {
5897     { HCBT_SETFOCUS, hook },
5898     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5899     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5900     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5901     { WM_SETFOCUS, sent|wparam, 0 },
5902     { WM_CTLCOLORBTN, sent|parent },
5903     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5904     { WM_APP, sent|wparam|lparam, 0, 0 },
5905     { 0 }
5906 };
5907 static const struct message WmKillFocusButtonSeq[] =
5908 {
5909     { HCBT_SETFOCUS, hook },
5910     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5911     { WM_KILLFOCUS, sent|wparam, 0 },
5912     { WM_CTLCOLORBTN, sent|parent },
5913     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5914     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5915     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5916     { WM_APP, sent|wparam|lparam, 0, 0 },
5917     { WM_PAINT, sent },
5918     { WM_CTLCOLORBTN, sent|parent },
5919     { 0 }
5920 };
5921 static const struct message WmSetFocusStaticSeq[] =
5922 {
5923     { HCBT_SETFOCUS, hook },
5924     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5925     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5926     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5927     { WM_SETFOCUS, sent|wparam, 0 },
5928     { WM_CTLCOLORSTATIC, sent|parent },
5929     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5930     { WM_COMMAND, sent|wparam|parent|optional, MAKEWPARAM(ID_BUTTON, BN_CLICKED) }, /* radio button */
5931     { WM_APP, sent|wparam|lparam, 0, 0 },
5932     { 0 }
5933 };
5934 static const struct message WmKillFocusStaticSeq[] =
5935 {
5936     { HCBT_SETFOCUS, hook },
5937     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5938     { WM_KILLFOCUS, sent|wparam, 0 },
5939     { WM_CTLCOLORSTATIC, sent|parent },
5940     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5941     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5942     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5943     { WM_APP, sent|wparam|lparam, 0, 0 },
5944     { WM_PAINT, sent },
5945     { WM_CTLCOLORSTATIC, sent|parent },
5946     { 0 }
5947 };
5948 static const struct message WmSetFocusOwnerdrawSeq[] =
5949 {
5950     { HCBT_SETFOCUS, hook },
5951     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5952     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5953     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5954     { WM_SETFOCUS, sent|wparam, 0 },
5955     { WM_CTLCOLORBTN, sent|parent },
5956     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x001040e4 },
5957     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5958     { WM_APP, sent|wparam|lparam, 0, 0 },
5959     { 0 }
5960 };
5961 static const struct message WmKillFocusOwnerdrawSeq[] =
5962 {
5963     { HCBT_SETFOCUS, hook },
5964     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5965     { WM_KILLFOCUS, sent|wparam, 0 },
5966     { WM_CTLCOLORBTN, sent|parent },
5967     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000040e4 },
5968     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5969     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5970     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5971     { WM_APP, sent|wparam|lparam, 0, 0 },
5972     { WM_PAINT, sent },
5973     { WM_CTLCOLORBTN, sent|parent },
5974     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
5975     { 0 }
5976 };
5977 static const struct message WmLButtonDownSeq[] =
5978 {
5979     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
5980     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5981     { HCBT_SETFOCUS, hook },
5982     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
5983     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5984     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5985     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
5986     { WM_CTLCOLORBTN, sent|defwinproc },
5987     { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
5988     { WM_CTLCOLORBTN, sent|defwinproc },
5989     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5990     { 0 }
5991 };
5992 static const struct message WmLButtonDownStaticSeq[] =
5993 {
5994     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
5995     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5996     { HCBT_SETFOCUS, hook },
5997     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
5998     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5999     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6000     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
6001     { WM_CTLCOLORSTATIC, sent|defwinproc },
6002     { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
6003     { WM_CTLCOLORSTATIC, sent|defwinproc },
6004     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6005     { 0 }
6006 };
6007 static const struct message WmLButtonUpSeq[] =
6008 {
6009     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6010     { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6011     { WM_CTLCOLORBTN, sent|defwinproc },
6012     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6013     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6014     { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6015     { 0 }
6016 };
6017 static const struct message WmLButtonUpStaticSeq[] =
6018 {
6019     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6020     { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6021     { WM_CTLCOLORSTATIC, sent|defwinproc },
6022     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6023     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6024     { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6025     { 0 }
6026 };
6027 static const struct message WmLButtonUpAutoSeq[] =
6028 {
6029     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6030     { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6031     { WM_CTLCOLORSTATIC, sent|defwinproc },
6032     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6033     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6034     { BM_SETCHECK, sent|defwinproc },
6035     { WM_CTLCOLORSTATIC, sent|defwinproc, 0, 0 },
6036     { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6037     { 0 }
6038 };
6039 static const struct message WmLButtonUpBrokenSeq[] =
6040 {
6041     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6042     { 0 }
6043 };
6044 static const struct message WmSetFontButtonSeq[] =
6045 {
6046     { WM_SETFONT, sent },
6047     { WM_PAINT, sent },
6048     { WM_ERASEBKGND, sent|defwinproc|optional },
6049     { WM_CTLCOLORBTN, sent|defwinproc },
6050     { WM_CTLCOLORBTN, sent|defwinproc|optional }, /* FIXME: Wine sends it twice for BS_OWNERDRAW */
6051     { 0 }
6052 };
6053 static const struct message WmSetFontStaticSeq[] =
6054 {
6055     { WM_SETFONT, sent },
6056     { WM_PAINT, sent },
6057     { WM_ERASEBKGND, sent|defwinproc|optional },
6058     { WM_CTLCOLORSTATIC, sent|defwinproc },
6059     { 0 }
6060 };
6061 static const struct message WmSetTextButtonSeq[] =
6062 {
6063     { WM_SETTEXT, sent },
6064     { WM_CTLCOLORBTN, sent|parent },
6065     { WM_CTLCOLORBTN, sent|parent },
6066     { WM_COMMAND, sent|parent|optional },
6067     { WM_DRAWITEM, sent|parent|optional },
6068     { 0 }
6069 };
6070 static const struct message WmSetTextStaticSeq[] =
6071 {
6072     { WM_SETTEXT, sent },
6073     { WM_CTLCOLORSTATIC, sent|parent },
6074     { WM_CTLCOLORSTATIC, sent|parent },
6075     { 0 }
6076 };
6077 static const struct message WmSetTextGroupSeq[] =
6078 {
6079     { WM_SETTEXT, sent },
6080     { WM_CTLCOLORSTATIC, sent|parent },
6081     { WM_CTLCOLORSTATIC, sent|parent|optional }, /* FIXME: Missing in Wine */
6082     { WM_CTLCOLORSTATIC, sent|parent|optional }, /* FIXME: Missing in Wine */
6083     { 0 }
6084 };
6085 static const struct message WmSetTextInvisibleSeq[] =
6086 {
6087     { WM_SETTEXT, sent },
6088     { 0 }
6089 };
6090 static const struct message WmSetStyleButtonSeq[] =
6091 {
6092     { BM_SETSTYLE, sent },
6093     { WM_APP, sent|wparam|lparam, 0, 0 },
6094     { WM_PAINT, sent },
6095     { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6096     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6097     { WM_CTLCOLORBTN, sent|parent },
6098     { 0 }
6099 };
6100 static const struct message WmSetStyleStaticSeq[] =
6101 {
6102     { BM_SETSTYLE, sent },
6103     { WM_APP, sent|wparam|lparam, 0, 0 },
6104     { WM_PAINT, sent },
6105     { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6106     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6107     { WM_CTLCOLORSTATIC, sent|parent },
6108     { 0 }
6109 };
6110 static const struct message WmSetStyleUserSeq[] =
6111 {
6112     { BM_SETSTYLE, sent },
6113     { WM_APP, sent|wparam|lparam, 0, 0 },
6114     { WM_PAINT, sent },
6115     { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6116     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6117     { WM_CTLCOLORBTN, sent|parent },
6118     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_PAINT) },
6119     { 0 }
6120 };
6121 static const struct message WmSetStyleOwnerdrawSeq[] =
6122 {
6123     { BM_SETSTYLE, sent },
6124     { WM_APP, sent|wparam|lparam, 0, 0 },
6125     { WM_PAINT, sent },
6126     { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
6127     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6128     { WM_CTLCOLORBTN, sent|parent },
6129     { WM_CTLCOLORBTN, sent|parent|optional }, /* Win9x doesn't send it */
6130     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
6131     { 0 }
6132 };
6133 static const struct message WmSetStateButtonSeq[] =
6134 {
6135     { BM_SETSTATE, sent },
6136     { WM_CTLCOLORBTN, sent|parent },
6137     { WM_APP, sent|wparam|lparam, 0, 0 },
6138     { 0 }
6139 };
6140 static const struct message WmSetStateStaticSeq[] =
6141 {
6142     { BM_SETSTATE, sent },
6143     { WM_CTLCOLORSTATIC, sent|parent },
6144     { WM_APP, sent|wparam|lparam, 0, 0 },
6145     { 0 }
6146 };
6147 static const struct message WmSetStateUserSeq[] =
6148 {
6149     { BM_SETSTATE, sent },
6150     { WM_CTLCOLORBTN, sent|parent },
6151     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_HILITE) },
6152     { WM_APP, sent|wparam|lparam, 0, 0 },
6153     { 0 }
6154 };
6155 static const struct message WmSetStateOwnerdrawSeq[] =
6156 {
6157     { BM_SETSTATE, sent },
6158     { WM_CTLCOLORBTN, sent|parent },
6159     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000120e4 },
6160     { WM_APP, sent|wparam|lparam, 0, 0 },
6161     { 0 }
6162 };
6163 static const struct message WmClearStateButtonSeq[] =
6164 {
6165     { BM_SETSTATE, sent },
6166     { WM_CTLCOLORBTN, sent|parent },
6167     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_UNHILITE) },
6168     { WM_APP, sent|wparam|lparam, 0, 0 },
6169     { 0 }
6170 };
6171 static const struct message WmDisableButtonSeq[] =
6172 {
6173     { WM_LBUTTONDOWN, sent },
6174     { BM_SETSTATE, sent|defwinproc },
6175     { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6176     { WM_CTLCOLORBTN, sent|optional },
6177     { WM_LBUTTONUP, sent },
6178     { BM_SETSTATE, sent|defwinproc },
6179     { WM_CTLCOLORBTN, sent|defwinproc|optional },
6180     { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6181     { BM_SETCHECK, sent|defwinproc|optional },
6182     { WM_CTLCOLORBTN, sent|optional },
6183     { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6184     { WM_CAPTURECHANGED, sent|defwinproc },
6185     { WM_COMMAND, sent },
6186     { 0 }
6187 };
6188 static const struct message WmClearStateOwnerdrawSeq[] =
6189 {
6190     { BM_SETSTATE, sent },
6191     { WM_CTLCOLORBTN, sent|parent },
6192     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000020e4 },
6193     { WM_APP, sent|wparam|lparam, 0, 0 },
6194     { 0 }
6195 };
6196 static const struct message WmSetCheckIgnoredSeq[] =
6197 {
6198     { BM_SETCHECK, sent },
6199     { WM_APP, sent|wparam|lparam, 0, 0 },
6200     { 0 }
6201 };
6202 static const struct message WmSetCheckStaticSeq[] =
6203 {
6204     { BM_SETCHECK, sent },
6205     { WM_CTLCOLORSTATIC, sent|parent },
6206     { WM_APP, sent|wparam|lparam, 0, 0 },
6207     { 0 }
6208 };
6209 
6210 static WNDPROC old_button_proc;
6211 
6212 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6213 {
6214     static LONG defwndproc_counter = 0;
6215     LRESULT ret;
6216     struct recvd_message msg;
6217 
6218     if (ignore_message( message )) return 0;
6219 
6220     switch (message)
6221     {
6222     case WM_SYNCPAINT:
6223         break;
6224     case BM_SETSTATE:
6225         if (GetCapture())
6226             ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
6227 
6228         lParam = (ULONG_PTR)GetMenu(hwnd);
6229         goto log_it;
6230 
6231     case WM_GETDLGCODE:
6232         if (lParam)
6233         {
6234             MSG *msg = (MSG *)lParam;
6235             lParam = MAKELPARAM(msg->message, msg->wParam);
6236         }
6237         wParam = (ULONG_PTR)GetMenu(hwnd);
6238         goto log_it;
6239 
6240     case BM_SETCHECK:
6241     case BM_GETCHECK:
6242         lParam = (ULONG_PTR)GetMenu(hwnd);
6243         /* fall through */
6244 log_it:
6245     default:
6246         msg.hwnd = hwnd;
6247         msg.message = message;
6248         msg.flags = sent|wparam|lparam;
6249         if (defwndproc_counter) msg.flags |= defwinproc;
6250         msg.wParam = wParam;
6251         msg.lParam = lParam;
6252         msg.descr = "button";
6253         add_message(&msg);
6254     }
6255 
6256     defwndproc_counter++;
6257     ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
6258     defwndproc_counter--;
6259 
6260     return ret;
6261 }
6262 
6263 static void subclass_button(void)
6264 {
6265     WNDCLASSA cls;
6266 
6267     if (!GetClassInfoA(0, "button", &cls)) assert(0);
6268 
6269     old_button_proc = cls.lpfnWndProc;
6270 
6271     cls.hInstance = GetModuleHandleA(NULL);
6272     cls.lpfnWndProc = button_hook_proc;
6273     cls.lpszClassName = "my_button_class";
6274     UnregisterClassA(cls.lpszClassName, cls.hInstance);
6275     if (!RegisterClassA(&cls)) assert(0);
6276 }
6277 
6278 static void test_button_messages(void)
6279 {
6280     static const struct
6281     {
6282         DWORD style;
6283         DWORD dlg_code;
6284         const struct message *setfocus;
6285         const struct message *killfocus;
6286         const struct message *setstyle;
6287         const struct message *setstate;
6288         const struct message *clearstate;
6289         const struct message *setcheck;
6290         const struct message *lbuttondown;
6291         const struct message *lbuttonup;
6292         const struct message *setfont;
6293         const struct message *settext;
6294     } button[] = {
6295         { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
6296           WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
6297           WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq,
6298           WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6299           WmSetTextButtonSeq },
6300         { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
6301           WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
6302           WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq,
6303           WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6304           WmSetTextButtonSeq },
6305         { BS_CHECKBOX, DLGC_BUTTON,
6306           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6307           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6308           WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6309           WmSetTextStaticSeq },
6310         { BS_AUTOCHECKBOX, DLGC_BUTTON,
6311           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6312           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6313           WmLButtonDownStaticSeq, WmLButtonUpAutoSeq, WmSetFontStaticSeq,
6314           WmSetTextStaticSeq },
6315         { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
6316           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6317           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6318           WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6319           WmSetTextStaticSeq },
6320         { BS_3STATE, DLGC_BUTTON,
6321           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6322           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6323           WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6324           WmSetTextStaticSeq },
6325         { BS_AUTO3STATE, DLGC_BUTTON,
6326           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6327           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6328           WmLButtonDownStaticSeq, WmLButtonUpAutoSeq, WmSetFontStaticSeq,
6329           WmSetTextStaticSeq },
6330         { BS_GROUPBOX, DLGC_STATIC,
6331           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6332           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckIgnoredSeq,
6333           WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6334           WmSetTextGroupSeq },
6335         { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
6336           WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleUserSeq,
6337           WmSetStateUserSeq, WmClearStateButtonSeq, WmSetCheckIgnoredSeq,
6338           WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6339           WmSetTextButtonSeq },
6340         { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
6341           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6342           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6343           NULL /* avoid infinite loop */, WmLButtonUpBrokenSeq, WmSetFontStaticSeq,
6344           WmSetTextStaticSeq },
6345         { BS_OWNERDRAW, DLGC_BUTTON,
6346           WmSetFocusOwnerdrawSeq, WmKillFocusOwnerdrawSeq, WmSetStyleOwnerdrawSeq,
6347           WmSetStateOwnerdrawSeq, WmClearStateOwnerdrawSeq, WmSetCheckIgnoredSeq,
6348           WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6349           WmSetTextButtonSeq },
6350     };
6351     LOGFONTA logfont = { 0 };
6352     HFONT zfont, hfont2;
6353     unsigned int i;
6354     HWND hwnd, parent;
6355     DWORD dlg_code;
6356 
6357     /* selection with VK_SPACE should capture button window */
6358     hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP,
6359                            0, 0, 50, 14, 0, 0, 0, NULL);
6360     ok(hwnd != 0, "Failed to create button window\n");
6361     ReleaseCapture();
6362     SetFocus(hwnd);
6363     SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
6364     ok(GetCapture() == hwnd, "Should be captured on VK_SPACE WM_KEYDOWN\n");
6365     SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
6366     DestroyWindow(hwnd);
6367 
6368     subclass_button();
6369 
6370     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6371                              100, 100, 200, 200, 0, 0, 0, NULL);
6372     ok(parent != 0, "Failed to create parent window\n");
6373 
6374     memset(&logfont, 0, sizeof(logfont));
6375     logfont.lfHeight = -12;
6376     logfont.lfWeight = FW_NORMAL;
6377     strcpy(logfont.lfFaceName, "Tahoma");
6378 
6379     hfont2 = CreateFontIndirectA(&logfont);
6380     ok(hfont2 != NULL, "Failed to create Tahoma font\n");
6381 
6382     for (i = 0; i < ARRAY_SIZE(button); i++)
6383     {
6384         MSG msg;
6385         DWORD style, state;
6386         HFONT prevfont;
6387         char desc[64];
6388         HDC hdc;
6389 
6390         trace("button style %08x\n", button[i].style);
6391 
6392         hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_CHILD | BS_NOTIFY,
6393                                0, 0, 50, 14, parent, (HMENU)ID_BUTTON, 0, NULL);
6394         ok(hwnd != 0, "Failed to create button window\n");
6395 
6396         style = GetWindowLongA(hwnd, GWL_STYLE);
6397         style &= ~(WS_CHILD | BS_NOTIFY);
6398         /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
6399         if (button[i].style == BS_USERBUTTON)
6400             ok(style == BS_PUSHBUTTON, "expected style BS_PUSHBUTTON got %x\n", style);
6401         else
6402             ok(style == button[i].style, "expected style %x got %x\n", button[i].style, style);
6403 
6404         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
6405         ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
6406 
6407         ShowWindow(hwnd, SW_SHOW);
6408         UpdateWindow(hwnd);
6409         SetFocus(0);
6410         flush_events();
6411         SetFocus(0);
6412         flush_sequence();
6413 
6414         log_all_parent_messages++;
6415 
6416         ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
6417         SetFocus(hwnd);
6418         SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6419         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6420         ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
6421 
6422         SetFocus(0);
6423         SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6424         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6425         ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
6426 
6427         ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
6428 
6429         SendMessageA(hwnd, BM_SETSTYLE, button[i].style | BS_BOTTOM, TRUE);
6430         SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6431         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6432         ok_sequence(button[i].setstyle, "BM_SETSTYLE on a button", FALSE);
6433 
6434         style = GetWindowLongA(hwnd, GWL_STYLE);
6435         style &= ~(WS_VISIBLE | WS_CHILD | BS_NOTIFY);
6436         /* XP doesn't turn a BS_USERBUTTON into BS_PUSHBUTTON here! */
6437         ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6438 
6439         state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6440         ok(state == 0, "expected state 0, got %04x\n", state);
6441 
6442         flush_sequence();
6443 
6444         SendMessageA(hwnd, BM_SETSTATE, TRUE, 0);
6445         SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6446         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6447         ok_sequence(button[i].setstate, "BM_SETSTATE/TRUE on a button", FALSE);
6448 
6449         state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6450         ok(state == 0x0004, "expected state 0x0004, got %04x\n", state);
6451 
6452         style = GetWindowLongA(hwnd, GWL_STYLE);
6453         style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6454         ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6455 
6456         flush_sequence();
6457 
6458         SendMessageA(hwnd, BM_SETSTATE, FALSE, 0);
6459         SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6460         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6461         ok_sequence(button[i].clearstate, "BM_SETSTATE/FALSE on a button", FALSE);
6462 
6463         state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6464         ok(state == 0, "expected state 0, got %04x\n", state);
6465 
6466         style = GetWindowLongA(hwnd, GWL_STYLE);
6467         style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6468         ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6469 
6470         state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6471         ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
6472 
6473         flush_sequence();
6474 
6475         SendMessageA(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
6476         SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6477         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6478         ok_sequence(WmSetCheckIgnoredSeq, "BM_SETCHECK on a button", FALSE);
6479 
6480         state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6481         ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
6482 
6483         style = GetWindowLongA(hwnd, GWL_STYLE);
6484         style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6485         ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6486 
6487         flush_sequence();
6488 
6489         SendMessageA(hwnd, BM_SETCHECK, BST_CHECKED, 0);
6490         SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6491         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6492         ok_sequence(button[i].setcheck, "BM_SETCHECK on a button", FALSE);
6493 
6494         SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 1");
6495         sprintf(desc, "button[%i]: WM_SETTEXT on a visible button", i);
6496         ok_sequence(button[i].settext, desc, FALSE);
6497 
6498         ShowWindow(hwnd, SW_HIDE);
6499         flush_events();
6500         flush_sequence();
6501 
6502         SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 2");
6503         sprintf(desc, "button[%i]: WM_SETTEXT on an invisible button", i);
6504         ok_sequence(WmSetTextInvisibleSeq, desc, FALSE);
6505 
6506         ShowWindow(hwnd, SW_SHOW);
6507         ShowWindow(parent, SW_HIDE);
6508         flush_events();
6509         flush_sequence();
6510 
6511         SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 3");
6512         sprintf(desc, "button[%i]: WM_SETTEXT on an invisible button", i);
6513         ok_sequence(WmSetTextInvisibleSeq, desc, FALSE);
6514 
6515         ShowWindow(parent, SW_SHOW);
6516         flush_events();
6517 
6518         state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6519         if (button[i].style == BS_PUSHBUTTON ||
6520             button[i].style == BS_DEFPUSHBUTTON ||
6521             button[i].style == BS_GROUPBOX ||
6522             button[i].style == BS_USERBUTTON ||
6523             button[i].style == BS_OWNERDRAW)
6524             ok(state == BST_UNCHECKED, "expected check 0, got %04x\n", state);
6525         else
6526             ok(state == BST_CHECKED, "expected check 1, got %04x\n", state);
6527 
6528         style = GetWindowLongA(hwnd, GWL_STYLE);
6529         style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6530         if (button[i].style == BS_RADIOBUTTON ||
6531             button[i].style == BS_AUTORADIOBUTTON)
6532             ok(style == (button[i].style | WS_TABSTOP), "expected style %04x | WS_TABSTOP got %04x\n", button[i].style, style);
6533         else
6534             ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6535 
6536         log_all_parent_messages--;
6537 
6538         DestroyWindow(hwnd);
6539 
6540         hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP | WS_VISIBLE,
6541                                0, 0, 50, 14, 0, 0, 0, NULL);
6542         ok(hwnd != 0, "Failed to create button window\n");
6543 
6544         SetForegroundWindow(hwnd);
6545         flush_events();
6546 
6547         SetActiveWindow(hwnd);
6548         SetFocus(0);
6549         flush_sequence();
6550 
6551         if (button[i].lbuttondown)
6552         {
6553             SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
6554             sprintf(desc, "button[%i]: WM_LBUTTONDOWN on a button", i);
6555             ok_sequence(button[i].lbuttondown, desc, FALSE);
6556         }
6557 
6558         SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
6559         sprintf(desc, "button[%i]: WM_LBUTTONUP on a button", i);
6560         ok_sequence(button[i].lbuttonup, desc, FALSE);
6561 
6562         flush_sequence();
6563         zfont = GetStockObject(DEFAULT_GUI_FONT);
6564         SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
6565         UpdateWindow(hwnd);
6566         sprintf(desc, "button[%i]: WM_SETFONT on a button", i);
6567         ok_sequence(button[i].setfont, desc, FALSE);
6568 
6569         /* Test that original font is not selected back after painting */
6570         hdc = CreateCompatibleDC(0);
6571 
6572         prevfont = SelectObject(hdc, hfont2);
6573         ok(prevfont == GetStockObject(SYSTEM_FONT), "Unexpected default font\n");
6574         SendMessageA(hwnd, WM_PRINTCLIENT, (WPARAM)hdc, 0);
6575         ok(hfont2 != GetCurrentObject(hdc, OBJ_FONT), "button[%u]: unexpected font selected after WM_PRINTCLIENT\n", i);
6576         SelectObject(hdc, prevfont);
6577 
6578         prevfont = SelectObject(hdc, hfont2);
6579         ok(prevfont == GetStockObject(SYSTEM_FONT), "Unexpected default font\n");
6580         SendMessageA(hwnd, WM_PAINT, (WPARAM)hdc, 0);
6581         ok(hfont2 != GetCurrentObject(hdc, OBJ_FONT), "button[%u]: unexpected font selected after WM_PAINT\n", i);
6582         SelectObject(hdc, prevfont);
6583 
6584         DeleteDC(hdc);
6585 
6586         DestroyWindow(hwnd);
6587     }
6588 
6589     DeleteObject(hfont2);
6590     DestroyWindow(parent);
6591 
6592     /* Test if WM_LBUTTONDOWN and WM_LBUTTONUP to a disabled button leads to a WM_COMMAND for the parent */
6593 
6594     parent = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6595             100, 100, 200, 200, 0, 0, 0, NULL);
6596     ok (hwnd != 0, "Failed to create overlapped window\n");
6597 
6598     hwnd = CreateWindowExA(0, "my_button_class", "test", BS_DEFPUSHBUTTON | WS_VISIBLE | WS_CHILD,
6599                                    0, 0, 50, 14, parent, 0, 0, NULL);
6600 
6601     EnableWindow(hwnd, FALSE);
6602     flush_sequence();
6603     SendMessageA(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, 0);
6604     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
6605     ok_sequence(WmDisableButtonSeq, "Mouseclick on a disabled button", FALSE);
6606 
6607     DestroyWindow(hwnd);
6608     DestroyWindow(parent);
6609 }
6610 
6611 static void test_button_bm_get_set_image(void)
6612 {
6613     HWND hwnd;
6614     HDC hdc;
6615     HBITMAP hbmp1x1;
6616     HBITMAP hbmp2x2;
6617     HBITMAP hmask2x2;
6618     ICONINFO icon_info2x2;
6619     HICON hicon2x2;
6620     HBITMAP hbmp;
6621     HICON hicon;
6622     ICONINFO icon_info;
6623     BITMAP bm;
6624     DWORD default_style = BS_PUSHBUTTON | WS_TABSTOP | WS_POPUP | WS_VISIBLE;
6625     LRESULT ret;
6626 
6627     hdc = GetDC(0);
6628     hbmp1x1 = CreateCompatibleBitmap(hdc, 1, 1);
6629     hbmp2x2 = CreateCompatibleBitmap(hdc, 2, 2);
6630     ZeroMemory(&bm, sizeof(bm));
6631     ok(GetObjectW(hbmp1x1, sizeof(bm), &bm), "Expect GetObjectW() success\n");
6632     ok(bm.bmWidth == 1 && bm.bmHeight == 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
6633        bm.bmWidth, bm.bmHeight);
6634     ZeroMemory(&bm, sizeof(bm));
6635     ok(GetObjectW(hbmp2x2, sizeof(bm), &bm), "Expect GetObjectW() success\n");
6636     ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
6637        bm.bmWidth, bm.bmHeight);
6638 
6639     hmask2x2 = CreateCompatibleBitmap(hdc, 2, 2);
6640     ZeroMemory(&icon_info2x2, sizeof(icon_info2x2));
6641     icon_info2x2.fIcon = TRUE;
6642     icon_info2x2.hbmMask = hmask2x2;
6643     icon_info2x2.hbmColor = hbmp2x2;
6644     hicon2x2 = CreateIconIndirect(&icon_info2x2);
6645 
6646     ZeroMemory(&icon_info, sizeof(icon_info));
6647     ok(GetIconInfo(hicon2x2, &icon_info), "Expect GetIconInfo() success\n");
6648     ZeroMemory(&bm, sizeof(bm));
6649     ok(GetObjectW(icon_info.hbmColor, sizeof(bm), &bm), "Expect GetObjectW() success\n");
6650     ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
6651        bm.bmWidth, bm.bmHeight);
6652     DeleteObject(icon_info.hbmColor);
6653     DeleteObject(icon_info.hbmMask);
6654 
6655     /* Set bitmap with BS_BITMAP */
6656     hwnd = CreateWindowA("Button", "test", default_style | BS_BITMAP, 0, 0, 100, 100, 0, 0, 0, 0);
6657     ok(hwnd != NULL, "Expect hwnd not NULL\n");
6658     SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp1x1);
6659     hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_BITMAP, 0);
6660     ok(hbmp != 0, "Expect hbmp not 0\n");
6661     ZeroMemory(&bm, sizeof(bm));
6662     ok(GetObjectW(hbmp, sizeof(bm), &bm), "Expect GetObjectW() success\n");
6663     ok(bm.bmWidth == 1 && bm.bmHeight == 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
6664        bm.bmWidth, bm.bmHeight);
6665     DestroyWindow(hwnd);
6666 
6667     /* Set bitmap without BS_BITMAP */
6668     hwnd = CreateWindowA("Button", "test", default_style, 0, 0, 100, 100, 0, 0, 0, 0);
6669     ok(hwnd != NULL, "Expect hwnd not NULL\n");
6670     ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp1x1);
6671     ok(ret == 0, "Expect ret to be 0\n");
6672     hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_BITMAP, 0);
6673     ok(hbmp == NULL, "Expect hbmp to be NULL\n");
6674     DestroyWindow(hwnd);
6675 
6676     /* Set icon with BS_ICON */
6677     hwnd = CreateWindowA("Button", "test", default_style | BS_ICON, 0, 0, 100, 100, 0, 0, 0, 0);
6678     ok(hwnd != NULL, "Expect hwnd not NULL\n");
6679     SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hicon2x2);
6680     hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_ICON, 0);
6681     ok(hicon != NULL, "Expect hicon not NULL\n");
6682     ZeroMemory(&icon_info, sizeof(icon_info));
6683     ok(GetIconInfo(hicon, &icon_info), "Expect GetIconInfo() success\n");
6684     ZeroMemory(&bm, sizeof(bm));
6685     ok(GetObjectW(icon_info.hbmColor, sizeof(bm), &bm), "Expect GetObjectW() success\n");
6686     ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
6687        bm.bmWidth, bm.bmHeight);
6688     DeleteObject(icon_info.hbmColor);
6689     DeleteObject(icon_info.hbmMask);
6690     DestroyWindow(hwnd);
6691 
6692     /* Set icon without BS_ICON */
6693     hwnd = CreateWindowA("Button", "test", default_style, 0, 0, 100, 100, 0, 0, 0, 0);
6694     ok(hwnd != NULL, "Expect hwnd not NULL\n");
6695     ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hicon2x2);
6696     ok(ret == 0, "Expect ret to be 0\n");
6697     hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_ICON, 0);
6698     ok(hicon == NULL, "Expect hicon to be NULL\n");
6699     DestroyWindow(hwnd);
6700 
6701     /* Set icon with BS_BITMAP */
6702     hwnd = CreateWindowA("Button", "test", default_style | BS_BITMAP, 0, 0, 100, 100, 0, 0, 0, 0);
6703     ok(hwnd != NULL, "Expect hwnd to be not NULL\n");
6704     ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hicon2x2);
6705     ok(ret == 0, "Expect ret to be 0\n");
6706     hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_ICON, 0);
6707     ok(hicon == NULL, "Expect hicon to be NULL\n");
6708     DestroyWindow(hwnd);
6709 
6710     /* Set bitmap with BS_ICON */
6711     hwnd = CreateWindowA("Button", "test", default_style | BS_ICON, 0, 0, 100, 100, 0, 0, 0, 0);
6712     ok(hwnd != NULL, "Expect hwnd to be not NULL\n");
6713     ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp1x1);
6714     ok(ret == 0, "Expect ret to be 0\n");
6715     hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_BITMAP, 0);
6716     ok(hbmp == NULL, "Expect hbmp to be NULL\n");
6717     DestroyWindow(hwnd);
6718 
6719     DestroyIcon(hicon2x2);
6720     DeleteObject(hmask2x2);
6721     DeleteObject(hbmp2x2);
6722     DeleteObject(hbmp1x1);
6723     ReleaseDC(0, hdc);
6724 }
6725 
6726 #define ID_RADIO1 501
6727 #define ID_RADIO2 502
6728 #define ID_RADIO3 503
6729 #define ID_TEXT   504
6730 
6731 static const struct message auto_radio_button_BM_CLICK[] =
6732 {
6733     { BM_CLICK, sent|wparam|lparam, 0, 0 },
6734     { WM_LBUTTONDOWN, sent|wparam|lparam|defwinproc, 0, 0 },
6735     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6736     { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO2 },
6737     { WM_CTLCOLORSTATIC, sent|parent },
6738     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6739     { WM_LBUTTONUP, sent|wparam|lparam|defwinproc, 0, 0 },
6740     { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO2 },
6741     { WM_CTLCOLORSTATIC, sent|parent },
6742     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6743     { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO2, 0 },
6744     { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO2 },
6745     { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO1, 0 },
6746     { BM_SETCHECK, sent|wparam|lparam|defwinproc, 0, ID_RADIO1 },
6747     { WM_CTLCOLORSTATIC, sent|parent },
6748     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6749     { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO3, 0 },
6750     { BM_SETCHECK, sent|wparam|lparam|defwinproc, 0, ID_RADIO3 },
6751     { WM_CTLCOLORSTATIC, sent|parent },
6752     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6753     { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_TEXT, 0 },
6754     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6755     { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
6756     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO2, BN_CLICKED) },
6757     { WM_NCHITTEST, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6758     { WM_SETCURSOR, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6759     { WM_MOUSEMOVE, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6760     { 0 }
6761 };
6762 
6763 static const struct message auto_radio_button_VK_UP_child[] =
6764 {
6765     { WM_KEYDOWN, sent|wparam|lparam, VK_UP, 0 },
6766     { WM_KEYUP, sent|wparam|lparam, VK_UP, 0 },
6767     { 0 }
6768 };
6769 
6770 static const struct message auto_radio_button_VK_UP_parent[] =
6771 {
6772     { WM_KEYDOWN, sent|wparam|lparam|parent, VK_UP, 0 },
6773     { WM_KEYUP, sent|wparam|lparam|parent, VK_UP, 0 },
6774     { 0 }
6775 };
6776 
6777 static const struct message auto_radio_button_VK_UP_dialog[] =
6778 {
6779     { WM_GETDLGCODE, sent|parent, 0, 0 },
6780 
6781     /* optional trailer seen on some windows setups */
6782     { WM_CHANGEUISTATE, sent|optional },
6783     { WM_UPDATEUISTATE, sent|optional },
6784     { WM_UPDATEUISTATE, sent|optional },
6785     { WM_UPDATEUISTATE, sent|optional },
6786     { WM_UPDATEUISTATE, sent|optional },
6787     { WM_UPDATEUISTATE, sent|optional },
6788     { WM_UPDATEUISTATE, sent|optional },
6789     { WM_UPDATEUISTATE, sent|optional },
6790     { WM_UPDATEUISTATE, sent|optional },
6791     { WM_UPDATEUISTATE, sent|optional },
6792     { WM_UPDATEUISTATE, sent|optional },
6793     { WM_UPDATEUISTATE, sent|optional },
6794     { WM_UPDATEUISTATE, sent|optional },
6795     { WM_UPDATEUISTATE, sent|optional },
6796     { WM_UPDATEUISTATE, sent|optional },
6797     { WM_UPDATEUISTATE, sent|optional },
6798     { WM_UPDATEUISTATE, sent|optional },
6799     { WM_UPDATEUISTATE, sent|optional },
6800     { WM_UPDATEUISTATE, sent|optional },
6801     { WM_CTLCOLORSTATIC, sent|parent|optional },
6802     { WM_CTLCOLORSTATIC, sent|parent|optional },
6803     { WM_CTLCOLORSTATIC, sent|parent|optional },
6804     { WM_UPDATEUISTATE, sent|optional },
6805     { WM_CTLCOLORSTATIC, sent|parent|optional },
6806     { WM_CTLCOLORSTATIC, sent|parent|optional },
6807     { WM_UPDATEUISTATE, sent|optional },
6808     { WM_CTLCOLORBTN, sent|parent|optional },
6809     { WM_CTLCOLORBTN, sent|parent|optional },
6810     { WM_UPDATEUISTATE, sent|optional },
6811     { WM_CTLCOLORSTATIC, sent|parent|optional },
6812     { WM_CTLCOLORSTATIC, sent|parent|optional },
6813     { 0 }
6814 };
6815 
6816 static const struct message auto_radio_button_VK_DOWN_dialog[] =
6817 {
6818     { WM_GETDLGCODE, sent|parent, 0, 0 },
6819     { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, MAKELPARAM(WM_KEYDOWN, VK_DOWN) },
6820     { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
6821     { HCBT_SETFOCUS, hook },
6822     { WM_KILLFOCUS, sent, 0, 0 },
6823     { WM_CTLCOLORSTATIC, sent|parent },
6824     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO3, BN_KILLFOCUS) },
6825     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6826     { WM_SETFOCUS, sent, 0, 0 },
6827     { WM_CTLCOLORSTATIC, sent|parent },
6828     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_SETFOCUS) },
6829     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_CLICKED) },
6830     { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
6831     { WM_GETDLGCODE, sent|parent, 0, 0 },
6832     { DM_GETDEFID, sent|parent, 0, 0 },
6833     { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
6834     { BM_CLICK, sent|wparam|lparam, 1, 0 },
6835     { WM_LBUTTONDOWN, sent|wparam|lparam|defwinproc, 0, 0 },
6836     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6837     { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO1 },
6838     { WM_CTLCOLORSTATIC, sent|parent },
6839     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6840     { WM_LBUTTONUP, sent|wparam|lparam|defwinproc, 0, 0 },
6841     { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO1 },
6842     { WM_CTLCOLORSTATIC, sent|parent },
6843     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6844     { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO1, 0 },
6845     { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO1 },
6846     { WM_CTLCOLORSTATIC, sent|parent },
6847     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6848     { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO3, 0 },
6849     { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO3 },
6850     { WM_CTLCOLORSTATIC, sent|parent },
6851     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6852     { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_TEXT, 0 },
6853     { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO2, 0 },
6854     { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO2 },
6855     { WM_CTLCOLORSTATIC, sent|parent },
6856     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6857     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6858     { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
6859     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_CLICKED) },
6860     { WM_NCHITTEST, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6861     { WM_SETCURSOR, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6862     { WM_MOUSEMOVE, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6863     { WM_PAINT, sent },
6864     { WM_CTLCOLORSTATIC, sent|parent },
6865     { 0 }
6866 };
6867 
6868 static const struct message auto_radio_button_VK_DOWN_radio3[] =
6869 {
6870     { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
6871     { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO2 },
6872     { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO3 },
6873     { WM_GETDLGCODE, sent|parent, 0, 0 },
6874     { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, MAKELPARAM(WM_KEYDOWN, VK_DOWN) },
6875     { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
6876     { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
6877     { WM_GETDLGCODE, sent|wparam|lparam|parent, 0, 0 },
6878     { WM_USER, sent|parent, 0, 0 },
6879     { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
6880     { 0 }
6881 };
6882 
6883 static const struct message auto_radio_button_VK_UP_radio1[] =
6884 {
6885     { WM_GETDLGCODE, sent|parent, 0, 0 },
6886     { 0 }
6887 };
6888 
6889 static INT_PTR WINAPI radio_test_dlg_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
6890 {
6891     ParentMsgCheckProcA(hwnd, msg, wp, lp);
6892     return 1;
6893 }
6894 
6895 static void test_autoradio_BM_CLICK(void)
6896 {
6897     HWND parent, radio1, radio2, radio3;
6898     RECT rc;
6899     MSG msg;
6900     DWORD ret;
6901 
6902     subclass_button();
6903 
6904     parent = CreateDialogParamA(0, "AUTORADIO_TEST_DIALOG_1", 0, radio_test_dlg_proc, 0);
6905     ok(parent != 0, "failed to create parent window\n");
6906 
6907     radio1 = GetDlgItem(parent, ID_RADIO1);
6908     radio2 = GetDlgItem(parent, ID_RADIO2);
6909     radio3 = GetDlgItem(parent, ID_RADIO3);
6910 
6911     /* this avoids focus messages in the generated sequence */
6912     SetFocus(radio2);
6913 
6914     flush_events();
6915     flush_sequence();
6916 
6917     ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6918     ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6919     ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6920     ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6921     ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6922     ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6923 
6924     SendMessageA(radio1, BM_SETCHECK, BST_CHECKED, 0);
6925 
6926     ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6927     ok(ret == BST_CHECKED, "got %08x\n", ret);
6928     ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6929     ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6930     ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6931     ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6932 
6933     SendMessageA(radio2, BM_SETCHECK, BST_CHECKED, 0);
6934 
6935     ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6936     ok(ret == BST_CHECKED, "got %08x\n", ret);
6937     ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6938     ok(ret == BST_CHECKED, "got %08x\n", ret);
6939     ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6940     ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6941 
6942     SendMessageA(radio3, BM_SETCHECK, BST_CHECKED, 0);
6943 
6944     ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6945     ok(ret == BST_CHECKED, "got %08x\n", ret);
6946     ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6947     ok(ret == BST_CHECKED, "got %08x\n", ret);
6948     ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6949     ok(ret == BST_CHECKED, "got %08x\n", ret);
6950 
6951     GetWindowRect(radio2, &rc);
6952     SetCursorPos(rc.left+1, rc.top+1);
6953 
6954     flush_events();
6955     flush_sequence();
6956 
6957     log_all_parent_messages++;
6958 
6959     SendMessageA(radio2, BM_CLICK, 0, 0);
6960     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6961     ok_sequence(auto_radio_button_BM_CLICK, "BM_CLICK on auto-radio button", FALSE);
6962 
6963     log_all_parent_messages--;
6964 
6965     ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6966     ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6967     ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6968     ok(ret == BST_CHECKED, "got %08x\n", ret);
6969     ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6970     ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6971 
6972     DestroyWindow(parent);
6973 }
6974 
6975 #define test_radio(r1, s1, r2, s2, r3, s3) test_radio_dbg(r1, s1, r2, s2, r3, s3, __LINE__)
6976 static void test_radio_dbg(HWND radio1, int state1, HWND radio2, int state2, HWND radio3, int state3, int line)
6977 {
6978     DWORD ret;
6979 
6980     ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6981     ok_(__FILE__,line)(ret == state1 ? BST_CHECKED : BST_UNCHECKED, "got %08x\n", ret);
6982     ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6983     ok_(__FILE__,line)(ret == state2 ? BST_CHECKED : BST_UNCHECKED, "got %08x\n", ret);
6984     ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6985     ok_(__FILE__,line)(ret == state3 ? BST_CHECKED : BST_UNCHECKED, "got %08x\n", ret);
6986 }
6987 
6988 static void set_radio(HWND radio1, int state1, HWND radio2, int state2, HWND radio3, int state3)
6989 {
6990     SendMessageA(radio1, BM_SETCHECK, state1 ? BST_CHECKED : BST_UNCHECKED, 0);
6991     SendMessageA(radio2, BM_SETCHECK, state2 ? BST_CHECKED : BST_UNCHECKED, 0);
6992     SendMessageA(radio3, BM_SETCHECK, state3 ? BST_CHECKED : BST_UNCHECKED, 0);
6993 }
6994 
6995 static void test_autoradio_kbd_move(void)
6996 {
6997     HWND parent, radio1, radio2, radio3, hwnd;
6998     RECT rc;
6999     MSG msg;
7000     DWORD ret;
7001 
7002     subclass_button();
7003 
7004     parent = CreateDialogParamA(0, "AUTORADIO_TEST_DIALOG_2", 0, radio_test_dlg_proc, 0);
7005     ok(parent != 0, "failed to create parent window\n");
7006 
7007     radio1 = GetDlgItem(parent, ID_RADIO1);
7008     radio2 = GetDlgItem(parent, ID_RADIO2);
7009     radio3 = GetDlgItem(parent, ID_RADIO3);
7010 
7011     flush_events();
7012     flush_sequence();
7013 
7014     test_radio(radio1, 0, radio2, 0, radio3, 0);
7015     set_radio(radio1, 1, radio2, 1, radio3, 1);
7016     test_radio(radio1, 1, radio2, 1, radio3, 1);
7017 
7018     SetFocus(radio3);
7019 
7020     flush_events();
7021     flush_sequence();
7022 
7023     log_all_parent_messages++;
7024 
7025     SendMessageA(radio3, WM_KEYDOWN, VK_UP, 0);
7026     SendMessageA(radio3, WM_KEYUP, VK_UP, 0);
7027     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7028     ok_sequence(auto_radio_button_VK_UP_child, "press/release VK_UP on auto-radio button", FALSE);
7029 
7030     test_radio(radio1, 1, radio2, 1, radio3, 1);
7031 
7032     flush_events();
7033     flush_sequence();
7034 
7035     DefDlgProcA(parent, WM_KEYDOWN, VK_UP, 0);
7036     DefDlgProcA(parent, WM_KEYUP, VK_UP, 0);
7037     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7038     ok_sequence(auto_radio_button_VK_UP_parent, "press/release VK_UP on dialog", FALSE);
7039 
7040     test_radio(radio1, 1, radio2, 1, radio3, 1);
7041 
7042     SetFocus(radio3);
7043     GetWindowRect(radio3, &rc);
7044 
7045     flush_events();
7046     flush_sequence();
7047 
7048     msg.hwnd = parent;
7049     msg.message = WM_KEYDOWN;
7050     msg.wParam = VK_UP;
7051     msg.lParam = 0;
7052     msg.pt.x = rc.left + 1;
7053     msg.pt.y = rc.top + 1;
7054     ret = IsDialogMessageA(parent, &msg);
7055     ok(ret, "IsDialogMessage should return TRUE\n");
7056     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7057 if (0) /* actual message sequence is different on every run in some Windows setups */
7058     ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #1", FALSE);
7059     /* what really matters is that nothing has changed */
7060     test_radio(radio1, 1, radio2, 1, radio3, 1);
7061 
7062     set_radio(radio1, 0, radio2, 1, radio3, 1);
7063     test_radio(radio1, 0, radio2, 1, radio3, 1);
7064 
7065     flush_events();
7066     flush_sequence();
7067 
7068     ret = IsDialogMessageA(parent, &msg);
7069     ok(ret, "IsDialogMessage should return TRUE\n");
7070     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7071 if (0) /* actual message sequence is different on every run in some Windows setups */
7072     ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #2", FALSE);
7073     /* what really matters is that nothing has changed */
7074     test_radio(radio1, 0, radio2, 1, radio3, 1);
7075 
7076     /* switch from radio3 ro radio1 */
7077     SetFocus(radio3);
7078     GetWindowRect(radio3, &rc);
7079 
7080     flush_events();
7081     flush_sequence();
7082 
7083     msg.hwnd = parent;
7084     msg.message = WM_KEYDOWN;
7085     msg.wParam = VK_DOWN;
7086     msg.lParam = 0;
7087     msg.pt.x = rc.left + 1;
7088     msg.pt.y = rc.top + 1;
7089     ret = IsDialogMessageA(parent, &msg);
7090     ok(ret, "IsDialogMessage should return TRUE\n");
7091     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7092     ok_sequence(auto_radio_button_VK_DOWN_dialog, "IsDialogMessage(VK_DOWN)", TRUE);
7093 
7094     test_radio(radio1, 1, radio2, 0, radio3, 0);
7095 
7096     hwnd = GetFocus();
7097     ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
7098     GetWindowRect(radio1, &rc);
7099 
7100     msg.hwnd = parent;
7101     msg.message = WM_KEYDOWN;
7102     msg.wParam = VK_DOWN;
7103     msg.lParam = 0;
7104     msg.pt.x = rc.left + 1;
7105     msg.pt.y = rc.top + 1;
7106     ret = IsDialogMessageA(parent, &msg);
7107     ok(ret, "IsDialogMessage should return TRUE\n");
7108     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7109     ok_sequence(auto_radio_button_VK_DOWN_radio3, "down to radio3", TRUE);
7110 
7111     test_radio(radio1, 1, radio2, 0, radio3, 0);
7112 
7113     hwnd = GetFocus();
7114     ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
7115 
7116     flush_events();
7117     flush_sequence();
7118 
7119     msg.hwnd = parent;
7120     msg.message = WM_KEYDOWN;
7121     msg.wParam = VK_UP;
7122     msg.lParam = 0;
7123     msg.pt.x = rc.left + 1;
7124     msg.pt.y = rc.top + 1;
7125     ret = IsDialogMessageA(parent, &msg);
7126     ok(ret, "IsDialogMessage should return TRUE\n");
7127     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7128     ok_sequence(auto_radio_button_VK_UP_radio1, "up to radio1", TRUE);
7129 
7130     test_radio(radio1, 1, radio2, 0, radio3, 0);
7131 
7132     hwnd = GetFocus();
7133     ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
7134 
7135     flush_events();
7136     flush_sequence();
7137 
7138     msg.hwnd = parent;
7139     msg.message = WM_KEYDOWN;
7140     msg.wParam = VK_UP;
7141     msg.lParam = 0;
7142     msg.pt.x = rc.left + 1;
7143     msg.pt.y = rc.top + 1;
7144     ret = IsDialogMessageA(parent, &msg);
7145     ok(ret, "IsDialogMessage should return TRUE\n");
7146     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7147 if (0) /* actual message sequence is different on every run in some Windows setups */
7148     ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #3", FALSE);
7149     /* what really matters is that nothing has changed */
7150     test_radio(radio1, 1, radio2, 0, radio3, 0);
7151 
7152     log_all_parent_messages--;
7153 
7154     DestroyWindow(parent);
7155 }
7156 
7157 /****************** static message test *************************/
7158 static const struct message WmSetFontStaticSeq2[] =
7159 {
7160     { WM_SETFONT, sent },
7161     { WM_PAINT, sent|defwinproc|optional },
7162     { WM_ERASEBKGND, sent|defwinproc|optional },
7163     { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
7164     { 0 }
7165 };
7166 
7167 static WNDPROC old_static_proc;
7168 
7169 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7170 {
7171     static LONG defwndproc_counter = 0;
7172     LRESULT ret;
7173     struct recvd_message msg;
7174 
7175     if (ignore_message( message )) return 0;
7176 
7177     msg.hwnd = hwnd;
7178     msg.message = message;
7179     msg.flags = sent|wparam|lparam;
7180     if (defwndproc_counter) msg.flags |= defwinproc;
7181     msg.wParam = wParam;
7182     msg.lParam = lParam;
7183     msg.descr = "static";
7184     add_message(&msg);
7185 
7186     defwndproc_counter++;
7187     ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
7188     defwndproc_counter--;
7189 
7190     return ret;
7191 }
7192 
7193 static void subclass_static(void)
7194 {
7195     WNDCLASSA cls;
7196 
7197     if (!GetClassInfoA(0, "static", &cls)) assert(0);
7198 
7199     old_static_proc = cls.lpfnWndProc;
7200 
7201     cls.hInstance = GetModuleHandleA(NULL);
7202     cls.lpfnWndProc = static_hook_proc;
7203     cls.lpszClassName = "my_static_class";
7204     UnregisterClassA(cls.lpszClassName, cls.hInstance);
7205     if (!RegisterClassA(&cls)) assert(0);
7206 }
7207 
7208 static void test_static_messages(void)
7209 {
7210     /* FIXME: make as comprehensive as the button message test */
7211     static const struct
7212     {
7213 	DWORD style;
7214 	DWORD dlg_code;
7215 	const struct message *setfont;
7216     } static_ctrl[] = {
7217 	{ SS_LEFT, DLGC_STATIC,
7218 	  WmSetFontStaticSeq2 }
7219     };
7220     unsigned int i;
7221     HWND hwnd;
7222     DWORD dlg_code;
7223 
7224     subclass_static();
7225 
7226     for (i = 0; i < ARRAY_SIZE(static_ctrl); i++)
7227     {
7228 	hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
7229 			       0, 0, 50, 14, 0, 0, 0, NULL);
7230 	ok(hwnd != 0, "Failed to create static window\n");
7231 
7232 	dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
7233 	ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
7234 
7235 	ShowWindow(hwnd, SW_SHOW);
7236 	UpdateWindow(hwnd);
7237 	SetFocus(0);
7238 	flush_sequence();
7239 
7240 	trace("static style %08x\n", static_ctrl[i].style);
7241 	SendMessageA(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
7242 	ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
7243 
7244 	DestroyWindow(hwnd);
7245     }
7246 }
7247 
7248 /****************** ComboBox message test *************************/
7249 #define ID_COMBOBOX 0x000f
7250 
7251 static const struct message SetCurSelComboSeq[] =
7252 {
7253     { CB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7254     { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7255     { LB_SETTOPINDEX, sent|wparam|lparam, 0, 0 },
7256     { LB_GETCURSEL, sent|wparam|lparam, 0, 0 },
7257     { LB_GETTEXTLEN, sent|wparam|lparam, 0, 0 },
7258     { LB_GETTEXTLEN, sent|wparam|lparam|optional, 0, 0 }, /* TODO: it's sent on all Windows versions */
7259     { LB_GETTEXT, sent|wparam, 0 },
7260     { WM_CTLCOLOREDIT, sent|parent },
7261     { LB_GETITEMDATA, sent|wparam|lparam, 0, 0 },
7262     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_COMBOBOX, 0x100010f3 },
7263     { 0 }
7264 };
7265 
7266 static const struct message SetCurSelComboSeq2[] =
7267 {
7268     { CB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7269     { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7270     { LB_SETTOPINDEX, sent|wparam|lparam, 0, 0 },
7271     { LB_GETCURSEL, sent|wparam|lparam, 0, 0 },
7272     { LB_GETTEXTLEN, sent|wparam|lparam, 0, 0 },
7273     { LB_GETTEXTLEN, sent|wparam|lparam|optional, 0, 0 }, /* TODO: it's sent on all Windows versions */
7274     { LB_GETTEXT, sent|wparam, 0 },
7275     { 0 }
7276 };
7277 
7278 static const struct message SetCurSelComboSeq_edit[] =
7279 {
7280     { CB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7281     { WM_SETTEXT, sent|wparam, 0 },
7282     { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
7283     { 0 }
7284 };
7285 
7286 static const struct message WmKeyDownComboSeq[] =
7287 {
7288     { WM_KEYDOWN, sent|wparam|lparam, VK_DOWN, 0 },
7289     { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(1000, LBN_SELCHANGE) },
7290     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDOK) },
7291     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELCHANGE) },
7292     { WM_CTLCOLOREDIT, sent|parent },
7293     { WM_KEYUP, sent|wparam|lparam, VK_DOWN, 0 },
7294     { 0 }
7295 };
7296 
7297 static const struct message WmSetPosComboSeq[] =
7298 {
7299     { WM_WINDOWPOSCHANGING, sent },
7300     { WM_NCCALCSIZE, sent|wparam, TRUE },
7301     { WM_CHILDACTIVATE, sent },
7302     { WM_WINDOWPOSCHANGED, sent },
7303     { WM_MOVE, sent|defwinproc },
7304     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
7305     { WM_WINDOWPOSCHANGING, sent|defwinproc },
7306     { WM_NCCALCSIZE, sent|defwinproc|wparam, TRUE },
7307     { WM_WINDOWPOSCHANGED, sent|defwinproc },
7308     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
7309     { 0 }
7310 };
7311 
7312 static const struct message WMSetFocusComboBoxSeq[] =
7313 {
7314     { WM_SETFOCUS, sent },
7315     { WM_KILLFOCUS, sent|parent },
7316     { WM_SETFOCUS, sent },
7317     { WM_COMMAND, sent|defwinproc|wparam, MAKEWPARAM(1001, EN_SETFOCUS) },
7318     { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, INT_MAX },
7319     { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7320     { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7321     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SETFOCUS) },
7322     { 0 }
7323 };
7324 
7325 static const struct message SetFocusButtonSeq[] =
7326 {
7327     { WM_KILLFOCUS, sent },
7328     { CB_GETCOMBOBOXINFO, sent|optional },/* Windows 2000 */
7329     { 0x0167, sent|optional },/* Undocumented message. Sent on all versions except Windows 2000 */
7330     { WM_LBUTTONUP, sent|defwinproc },
7331     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDCANCEL) },
7332     { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, 0 },
7333     { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7334     { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7335     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_KILLFOCUS) },
7336     { WM_CTLCOLORBTN, sent|parent },
7337     { 0 }
7338 };
7339 
7340 static const struct message SetFocusComboBoxSeq[] =
7341 {
7342     { WM_CTLCOLORBTN, sent|parent },
7343     { WM_SETFOCUS, sent },
7344     { WM_KILLFOCUS, sent|defwinproc },
7345     { WM_SETFOCUS, sent },
7346     { WM_COMMAND, sent|defwinproc|wparam, MAKEWPARAM(1001, EN_SETFOCUS) },
7347     { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, INT_MAX },
7348     { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7349     { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7350     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SETFOCUS) },
7351     { 0 }
7352 };
7353 
7354 static const struct message SetFocusButtonSeq2[] =
7355 {
7356     { WM_KILLFOCUS, sent },
7357     { CB_GETCOMBOBOXINFO, sent|optional },/* Windows 2000 */
7358     { 0x0167, sent|optional },/* Undocumented message. Sent on all versions except Windows 2000 */
7359     { WM_LBUTTONUP, sent|defwinproc },
7360     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDCANCEL) },
7361     { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, 0 },
7362     { WM_CTLCOLOREDIT, sent|defwinproc },
7363     { WM_CTLCOLOREDIT, sent|parent },
7364     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_KILLFOCUS) },
7365     { WM_CTLCOLORBTN, sent|parent },
7366     { 0 }
7367 };
7368 
7369 static WNDPROC old_combobox_proc, edit_window_proc, lbox_window_proc;
7370 
7371 static LRESULT CALLBACK combobox_edit_subclass_proc(HWND hwnd, UINT message,
7372         WPARAM wParam, LPARAM lParam)
7373 {
7374     static LONG defwndproc_counter = 0;
7375     LRESULT ret;
7376     struct recvd_message msg;
7377 
7378     /* do not log painting messages */
7379     if (message != WM_PAINT &&
7380         message != WM_NCPAINT &&
7381         message != WM_SYNCPAINT &&
7382         message != WM_ERASEBKGND &&
7383         message != WM_NCHITTEST &&
7384         message != WM_GETTEXT &&
7385         !ignore_message( message ))
7386     {
7387         msg.hwnd = hwnd;
7388         msg.message = message;
7389         msg.flags = sent|wparam|lparam;
7390         if (defwndproc_counter) msg.flags |= defwinproc;
7391         msg.wParam = wParam;
7392         msg.lParam = lParam;
7393         msg.descr = "combo edit";
7394         add_message(&msg);
7395     }
7396 
7397     defwndproc_counter++;
7398     ret = CallWindowProcA(edit_window_proc, hwnd, message, wParam, lParam);
7399     defwndproc_counter--;
7400 
7401     return ret;
7402 }
7403 
7404 static LRESULT CALLBACK combobox_lbox_subclass_proc(HWND hwnd, UINT message,
7405         WPARAM wParam, LPARAM lParam)
7406 {
7407     static LONG defwndproc_counter = 0;
7408     LRESULT ret;
7409     struct recvd_message msg;
7410 
7411     /* do not log painting messages */
7412     if (message != WM_PAINT &&
7413         message != WM_NCPAINT &&
7414         message != WM_SYNCPAINT &&
7415         message != WM_ERASEBKGND &&
7416         message != WM_NCHITTEST &&
7417         !ignore_message( message ))
7418     {
7419         msg.hwnd = hwnd;
7420         msg.message = message;
7421         msg.flags = sent|wparam|lparam;
7422         if (defwndproc_counter) msg.flags |= defwinproc;
7423         msg.wParam = wParam;
7424         msg.lParam = lParam;
7425         msg.descr = "combo lbox";
7426         add_message(&msg);
7427     }
7428 
7429     defwndproc_counter++;
7430     ret = CallWindowProcA(lbox_window_proc, hwnd, message, wParam, lParam);
7431     defwndproc_counter--;
7432 
7433     return ret;
7434 }
7435 
7436 static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7437 {
7438     static LONG defwndproc_counter = 0;
7439     LRESULT ret;
7440     struct recvd_message msg;
7441 
7442     /* do not log painting messages */
7443     if (message != WM_PAINT &&
7444         message != WM_NCPAINT &&
7445         message != WM_SYNCPAINT &&
7446         message != WM_ERASEBKGND &&
7447         message != WM_NCHITTEST &&
7448         message != WM_GETTEXT &&
7449         !ignore_message( message ))
7450     {
7451         msg.hwnd = hwnd;
7452         msg.message = message;
7453         msg.flags = sent|wparam|lparam;
7454         if (defwndproc_counter) msg.flags |= defwinproc;
7455         msg.wParam = wParam;
7456         msg.lParam = lParam;
7457         msg.descr = "combo";
7458         add_message(&msg);
7459     }
7460 
7461     defwndproc_counter++;
7462     ret = CallWindowProcA(old_combobox_proc, hwnd, message, wParam, lParam);
7463     defwndproc_counter--;
7464 
7465     return ret;
7466 }
7467 
7468 static void subclass_combobox(void)
7469 {
7470     WNDCLASSA cls;
7471 
7472     if (!GetClassInfoA(0, "ComboBox", &cls)) assert(0);
7473 
7474     old_combobox_proc = cls.lpfnWndProc;
7475 
7476     cls.hInstance = GetModuleHandleA(NULL);
7477     cls.lpfnWndProc = combobox_hook_proc;
7478     cls.lpszClassName = "my_combobox_class";
7479     UnregisterClassA(cls.lpszClassName, cls.hInstance);
7480     if (!RegisterClassA(&cls)) assert(0);
7481 }
7482 
7483 static void test_combobox_messages(void)
7484 {
7485     HWND parent, combo, button, edit, lbox;
7486     LRESULT ret;
7487     COMBOBOXINFO cbInfo;
7488     BOOL res;
7489 
7490     subclass_combobox();
7491 
7492     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7493                              100, 100, 200, 200, 0, 0, 0, NULL);
7494     ok(parent != 0, "Failed to create parent window\n");
7495     flush_sequence();
7496 
7497     combo = CreateWindowExA(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
7498                            0, 0, 100, 150, parent, (HMENU)ID_COMBOBOX, 0, NULL);
7499     ok(combo != 0, "Failed to create combobox window\n");
7500 
7501     UpdateWindow(combo);
7502 
7503     ret = SendMessageA(combo, WM_GETDLGCODE, 0, 0);
7504     ok(ret == (DLGC_WANTCHARS | DLGC_WANTARROWS), "wrong dlg_code %08lx\n", ret);
7505 
7506     ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
7507     ok(ret == 0, "expected 0, got %ld\n", ret);
7508     ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 1");
7509     ok(ret == 1, "expected 1, got %ld\n", ret);
7510     ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 2");
7511     ok(ret == 2, "expected 2, got %ld\n", ret);
7512 
7513     SendMessageA(combo, CB_SETCURSEL, 0, 0);
7514     SetFocus(combo);
7515     flush_sequence();
7516 
7517     log_all_parent_messages++;
7518     SendMessageA(combo, WM_KEYDOWN, VK_DOWN, 0);
7519     SendMessageA(combo, WM_KEYUP, VK_DOWN, 0);
7520     log_all_parent_messages--;
7521     ok_sequence(WmKeyDownComboSeq, "WM_KEYDOWN/VK_DOWN on a ComboBox", FALSE);
7522 
7523     flush_sequence();
7524     SetWindowPos(combo, 0, 10, 10, 120, 130, SWP_NOZORDER);
7525     ok_sequence(WmSetPosComboSeq, "repositioning messages on a ComboBox", FALSE);
7526 
7527     DestroyWindow(combo);
7528     DestroyWindow(parent);
7529 
7530     /* Start again. Test combobox text selection when getting and losing focus */
7531     parent = CreateWindowExA(0, "TestParentClass", "Parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7532                              10, 10, 300, 300, NULL, NULL, NULL, NULL);
7533     ok(parent != 0, "Failed to create parent window\n");
7534 
7535     combo = CreateWindowExA(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWN,
7536                             5, 5, 100, 100, parent, (HMENU)ID_COMBOBOX, NULL, NULL);
7537     ok(combo != 0, "Failed to create combobox window\n");
7538 
7539     cbInfo.cbSize = sizeof(COMBOBOXINFO);
7540     SetLastError(0xdeadbeef);
7541     res = GetComboBoxInfo(combo, &cbInfo);
7542     ok(res, "Failed to get COMBOBOXINFO structure; LastError: %u\n", GetLastError());
7543     edit = cbInfo.hwndItem;
7544 
7545     edit_window_proc = (WNDPROC)SetWindowLongPtrA(edit, GWLP_WNDPROC,
7546             (ULONG_PTR)combobox_edit_subclass_proc);
7547 
7548     button = CreateWindowExA(0, "Button", "OK", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
7549                              5, 50, 100, 20, parent, NULL,
7550                              (HINSTANCE)GetWindowLongPtrA(parent, GWLP_HINSTANCE), NULL);
7551     ok(button != 0, "Failed to create button window\n");
7552 
7553     flush_sequence();
7554     log_all_parent_messages++;
7555     SendMessageA(combo, WM_SETFOCUS, 0, (LPARAM)edit);
7556     log_all_parent_messages--;
7557     ok_sequence(WMSetFocusComboBoxSeq, "WM_SETFOCUS on a ComboBox", TRUE);
7558 
7559     flush_sequence();
7560     log_all_parent_messages++;
7561     SetFocus(button);
7562     log_all_parent_messages--;
7563     ok_sequence(SetFocusButtonSeq, "SetFocus on a Button", TRUE);
7564 
7565     SendMessageA(combo, WM_SETTEXT, 0, (LPARAM)"Wine Test");
7566 
7567     flush_sequence();
7568     log_all_parent_messages++;
7569     SetFocus(combo);
7570     log_all_parent_messages--;
7571     ok_sequence(SetFocusComboBoxSeq, "SetFocus on a ComboBox", TRUE);
7572 
7573     flush_sequence();
7574     log_all_parent_messages++;
7575     SetFocus(button);
7576     log_all_parent_messages--;
7577     ok_sequence(SetFocusButtonSeq2, "SetFocus on a Button (2)", TRUE);
7578 
7579     SetFocus(combo);
7580     SendMessageA(combo, WM_SETREDRAW, FALSE, 0);
7581     flush_sequence();
7582     log_all_parent_messages++;
7583     SendMessageA(combo, CB_SETCURSEL, 0, 0);
7584     log_all_parent_messages--;
7585     ok_sequence(SetCurSelComboSeq_edit, "CB_SETCURSEL on a ComboBox with edit control", FALSE);
7586 
7587     DestroyWindow(button);
7588     DestroyWindow(combo);
7589 
7590     combo = CreateWindowExA(0, "my_combobox_class", "test",
7591                             WS_CHILD | WS_VISIBLE | CBS_OWNERDRAWFIXED | CBS_DROPDOWNLIST,
7592                             5, 5, 100, 100, parent, (HMENU)ID_COMBOBOX, NULL, NULL);
7593     ok(combo != 0, "Failed to create combobox window\n");
7594 
7595     ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
7596     ok(ret == 0, "expected 0, got %ld\n", ret);
7597 
7598     cbInfo.cbSize = sizeof(COMBOBOXINFO);
7599     SetLastError(0xdeadbeef);
7600     res = GetComboBoxInfo(combo, &cbInfo);
7601     ok(res, "Failed to get COMBOBOXINFO structure; LastError: %u\n", GetLastError());
7602     lbox = cbInfo.hwndList;
7603     lbox_window_proc = (WNDPROC)SetWindowLongPtrA(lbox, GWLP_WNDPROC,
7604             (ULONG_PTR)combobox_lbox_subclass_proc);
7605     flush_sequence();
7606 
7607     log_all_parent_messages++;
7608     SendMessageA(combo, CB_SETCURSEL, 0, 0);
7609     log_all_parent_messages--;
7610     ok_sequence(SetCurSelComboSeq, "CB_SETCURSEL on a ComboBox", FALSE);
7611 
7612     ShowWindow(combo, SW_HIDE);
7613     flush_sequence();
7614     log_all_parent_messages++;
7615     SendMessageA(combo, CB_SETCURSEL, 0, 0);
7616     log_all_parent_messages--;
7617     ok_sequence(SetCurSelComboSeq2, "CB_SETCURSEL on a ComboBox", FALSE);
7618 
7619     DestroyWindow(combo);
7620     DestroyWindow(parent);
7621 }
7622 
7623 /****************** WM_IME_KEYDOWN message test *******************/
7624 
7625 static const struct message WmImeKeydownMsgSeq_0[] =
7626 {
7627     { WM_IME_KEYDOWN, wparam, VK_RETURN },
7628     { WM_CHAR, wparam, 'A' },
7629     { 0 }
7630 };
7631 
7632 static const struct message WmImeKeydownMsgSeq_1[] =
7633 {
7634     { WM_KEYDOWN, optional|wparam, VK_RETURN },
7635     { WM_CHAR,    optional|wparam, VK_RETURN },
7636     { 0 }
7637 };
7638 
7639 static LRESULT WINAPI wmime_keydown_procA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7640 {
7641     struct recvd_message msg;
7642 
7643     msg.hwnd = hwnd;
7644     msg.message = message;
7645     msg.flags = wparam|lparam;
7646     msg.wParam = wParam;
7647     msg.lParam = lParam;
7648     msg.descr = "wmime_keydown";
7649     add_message(&msg);
7650 
7651     return DefWindowProcA(hwnd, message, wParam, lParam);
7652 }
7653 
7654 static void register_wmime_keydown_class(void)
7655 {
7656     WNDCLASSA cls;
7657 
7658     ZeroMemory(&cls, sizeof(WNDCLASSA));
7659     cls.lpfnWndProc = wmime_keydown_procA;
7660     cls.hInstance = GetModuleHandleA(0);
7661     cls.lpszClassName = "wmime_keydown_class";
7662     if (!RegisterClassA(&cls)) assert(0);
7663 }
7664 
7665 static void test_wmime_keydown_message(void)
7666 {
7667     HWND hwnd;
7668     MSG msg;
7669 
7670     trace("Message sequences by WM_IME_KEYDOWN\n");
7671 
7672     register_wmime_keydown_class();
7673     hwnd = CreateWindowExA(0, "wmime_keydown_class", NULL, WS_OVERLAPPEDWINDOW,
7674                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
7675                            NULL, NULL, 0);
7676     flush_events();
7677     flush_sequence();
7678 
7679     SendMessageA(hwnd, WM_IME_KEYDOWN, VK_RETURN, 0x1c0001);
7680     SendMessageA(hwnd, WM_CHAR, 'A', 1);
7681     ok_sequence(WmImeKeydownMsgSeq_0, "WM_IME_KEYDOWN 0", FALSE);
7682 
7683     while ( PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) )
7684     {
7685         TranslateMessage(&msg);
7686         DispatchMessageA(&msg);
7687     }
7688     ok_sequence(WmImeKeydownMsgSeq_1, "WM_IME_KEYDOWN 1", FALSE);
7689 
7690     DestroyWindow(hwnd);
7691 }
7692 
7693 /************* painting message test ********************/
7694 
7695 void dump_region(HRGN hrgn)
7696 {
7697     DWORD i, size;
7698     RGNDATA *data = NULL;
7699     RECT *rect;
7700 
7701     if (!hrgn)
7702     {
7703         printf( "null region\n" );
7704         return;
7705     }
7706     if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
7707     if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
7708     GetRegionData( hrgn, size, data );
7709     printf("%d rects:", data->rdh.nCount );
7710     for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
7711         printf( " %s", wine_dbgstr_rect( rect ));
7712     printf("\n");
7713     HeapFree( GetProcessHeap(), 0, data );
7714 }
7715 
7716 #define check_update_rgn( hwnd, hrgn ) check_update_rgn_( __LINE__, hwnd, hrgn )
7717 static void check_update_rgn_( int line, HWND hwnd, HRGN hrgn )
7718 {
7719     INT ret;
7720     RECT r1, r2;
7721     HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
7722     HRGN update = CreateRectRgn( 0, 0, 0, 0 );
7723 
7724     ret = GetUpdateRgn( hwnd, update, FALSE );
7725     ok( ret != ERROR, "GetUpdateRgn failed\n" );
7726     if (ret == NULLREGION)
7727     {
7728         ok_(__FILE__,line)( !hrgn, "Update region shouldn't be empty\n" );
7729     }
7730     else
7731     {
7732         if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
7733         {
7734             ok_(__FILE__,line)( 0, "Regions are different\n" );
7735             if (winetest_debug > 0)
7736             {
7737                 printf( "Update region: " );
7738                 dump_region( update );
7739                 printf( "Wanted region: " );
7740                 dump_region( hrgn );
7741             }
7742         }
7743     }
7744     GetRgnBox( update, &r1 );
7745     GetUpdateRect( hwnd, &r2, FALSE );
7746     ok_(__FILE__,line)( EqualRect( &r1, &r2 ), "Rectangles are different: %s / %s\n",
7747                         wine_dbgstr_rect( &r1 ), wine_dbgstr_rect( &r2 ));
7748 
7749     DeleteObject( tmp );
7750     DeleteObject( update );
7751 }
7752 
7753 static const struct message WmInvalidateRgn[] = {
7754     { WM_NCPAINT, sent },
7755     { WM_GETTEXT, sent|defwinproc|optional },
7756     { 0 }
7757 };
7758 
7759 static const struct message WmGetUpdateRect[] = {
7760     { WM_NCPAINT, sent },
7761     { WM_GETTEXT, sent|defwinproc|optional },
7762     { WM_PAINT, sent },
7763     { 0 }
7764 };
7765 
7766 static const struct message WmInvalidateFull[] = {
7767     { WM_NCPAINT, sent|wparam, 1 },
7768     { WM_GETTEXT, sent|defwinproc|optional },
7769     { 0 }
7770 };
7771 
7772 static const struct message WmInvalidateErase[] = {
7773     { WM_NCPAINT, sent|wparam, 1 },
7774     { WM_GETTEXT, sent|defwinproc|optional },
7775     { WM_ERASEBKGND, sent },
7776     { 0 }
7777 };
7778 
7779 static const struct message WmInvalidatePaint[] = {
7780     { WM_PAINT, sent },
7781     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
7782     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7783     { 0 }
7784 };
7785 
7786 static const struct message WmInvalidateErasePaint[] = {
7787     { WM_PAINT, sent },
7788     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
7789     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7790     { WM_ERASEBKGND, sent|beginpaint|optional },
7791     { 0 }
7792 };
7793 
7794 static const struct message WmInvalidateErasePaint2[] = {
7795     { WM_PAINT, sent },
7796     { WM_NCPAINT, sent|beginpaint },
7797     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7798     { WM_ERASEBKGND, sent|beginpaint|optional },
7799     { 0 }
7800 };
7801 
7802 static const struct message WmErase[] = {
7803     { WM_ERASEBKGND, sent },
7804     { 0 }
7805 };
7806 
7807 static const struct message WmPaint[] = {
7808     { WM_PAINT, sent },
7809     { 0 }
7810 };
7811 
7812 static const struct message WmParentOnlyPaint[] = {
7813     { WM_PAINT, sent|parent },
7814     { 0 }
7815 };
7816 
7817 static const struct message WmInvalidateParent[] = {
7818     { WM_NCPAINT, sent|parent },
7819     { WM_GETTEXT, sent|defwinproc|parent|optional },
7820     { WM_ERASEBKGND, sent|parent },
7821     { 0 }
7822 };
7823 
7824 static const struct message WmInvalidateParentChild[] = {
7825     { WM_NCPAINT, sent|parent },
7826     { WM_GETTEXT, sent|defwinproc|parent|optional },
7827     { WM_ERASEBKGND, sent|parent },
7828     { WM_NCPAINT, sent },
7829     { WM_GETTEXT, sent|defwinproc|optional },
7830     { WM_ERASEBKGND, sent },
7831     { 0 }
7832 };
7833 
7834 static const struct message WmInvalidateParentChild2[] = {
7835     { WM_ERASEBKGND, sent|parent },
7836     { WM_NCPAINT, sent },
7837     { WM_GETTEXT, sent|defwinproc|optional },
7838     { WM_ERASEBKGND, sent },
7839     { 0 }
7840 };
7841 
7842 static const struct message WmParentPaint[] = {
7843     { WM_PAINT, sent|parent },
7844     { WM_PAINT, sent },
7845     { 0 }
7846 };
7847 
7848 static const struct message WmParentPaintNc[] = {
7849     { WM_PAINT, sent|parent },
7850     { WM_PAINT, sent },
7851     { WM_NCPAINT, sent|beginpaint },
7852     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7853     { WM_ERASEBKGND, sent|beginpaint|optional },
7854     { 0 }
7855 };
7856 
7857 static const struct message WmChildPaintNc[] = {
7858     { WM_PAINT, sent },
7859     { WM_NCPAINT, sent|beginpaint },
7860     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7861     { WM_ERASEBKGND, sent|beginpaint|optional },
7862     { 0 }
7863 };
7864 
7865 static const struct message WmParentErasePaint[] = {
7866     { WM_PAINT, sent|parent },
7867     { WM_NCPAINT, sent|parent|beginpaint },
7868     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
7869     { WM_ERASEBKGND, sent|parent|beginpaint|optional },
7870     { WM_PAINT, sent },
7871     { WM_NCPAINT, sent|beginpaint },
7872     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7873     { WM_ERASEBKGND, sent|beginpaint|optional },
7874     { 0 }
7875 };
7876 
7877 static const struct message WmParentOnlyNcPaint[] = {
7878     { WM_PAINT, sent|parent },
7879     { WM_NCPAINT, sent|parent|beginpaint },
7880     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
7881     { 0 }
7882 };
7883 
7884 static const struct message WmSetParentStyle[] = {
7885     { WM_STYLECHANGING, sent|parent },
7886     { WM_STYLECHANGED, sent|parent },
7887     { 0 }
7888 };
7889 
7890 static void test_paint_messages(void)
7891 {
7892     BOOL ret;
7893     RECT rect, rect2;
7894     POINT pt;
7895     MSG msg;
7896     HWND hparent, hchild;
7897     HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
7898     HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
7899     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
7900                                 100, 100, 200, 200, 0, 0, 0, NULL);
7901     ok (hwnd != 0, "Failed to create overlapped window\n");
7902 
7903     ShowWindow( hwnd, SW_SHOW );
7904     UpdateWindow( hwnd );
7905     flush_events();
7906     flush_sequence();
7907 
7908     check_update_rgn( hwnd, 0 );
7909     SetRectRgn( hrgn, 10, 10, 20, 20 );
7910     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
7911     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7912     check_update_rgn( hwnd, hrgn );
7913     SetRectRgn( hrgn2, 20, 20, 30, 30 );
7914     ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
7915     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7916     CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
7917     check_update_rgn( hwnd, hrgn );
7918     /* validate everything */
7919     ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7920     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7921     check_update_rgn( hwnd, 0 );
7922 
7923     /* test empty region */
7924     SetRectRgn( hrgn, 10, 10, 10, 15 );
7925     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
7926     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7927     check_update_rgn( hwnd, 0 );
7928     /* test empty rect */
7929     SetRect( &rect, 10, 10, 10, 15 );
7930     ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
7931     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7932     check_update_rgn( hwnd, 0 );
7933 
7934     /* flush pending messages */
7935     flush_events();
7936     flush_sequence();
7937 
7938     GetClientRect( hwnd, &rect );
7939     SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
7940     /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
7941      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
7942      */
7943     SetRectEmpty( &rect );
7944     ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) failed\n");
7945     check_update_rgn( hwnd, hrgn );
7946     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
7947     flush_events();
7948     ok_sequence( WmPaint, "Paint", FALSE );
7949     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7950     check_update_rgn( hwnd, 0 );
7951 
7952     SetRectEmpty( &rect );
7953     ok(RedrawWindow(0, &rect, 0, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
7954        "RedrawWindow failed\n");
7955     check_update_rgn( hwnd, 0 );
7956 
7957     SetRectEmpty( &rect );
7958     ok(RedrawWindow(0, &rect, 0, RDW_ALLCHILDREN | RDW_VALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
7959        "RedrawWindow failed\n");
7960     check_update_rgn( hwnd, 0 );
7961 
7962     GetWindowRect( hwnd, &rect );
7963     ok(RedrawWindow(0, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
7964        "RedrawWindow failed\n");
7965     check_update_rgn( hwnd, 0 );
7966 
7967     flush_events();
7968     ok(RedrawWindow(0, &rect, 0, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
7969        "RedrawWindow failed\n");
7970     check_update_rgn( hwnd, hrgn );
7971     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
7972     flush_events();
7973     ok_sequence( WmPaint, "Paint", FALSE );
7974     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7975     check_update_rgn( hwnd, 0 );
7976 
7977     ok(RedrawWindow(GetDesktopWindow(), &rect, 0,
7978                     RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
7979        "RedrawWindow failed\n");
7980     ret = GetUpdateRgn( hwnd, hrgn2, FALSE );
7981     ok( ret == NULLREGION || broken(ret == SIMPLEREGION), /* <= win7 */
7982         "region should be null (%d)\n", ret );
7983     if (ret == SIMPLEREGION) ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
7984     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7985     flush_events();
7986 
7987     ok(RedrawWindow(GetDesktopWindow(), NULL, 0,
7988                     RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
7989        "RedrawWindow failed\n");
7990     ret = GetUpdateRgn( hwnd, hrgn2, FALSE );
7991     ok( ret == NULLREGION || broken(ret == SIMPLEREGION), /* <= win7 */
7992         "region should be null (%d)\n", ret );
7993     if (ret == SIMPLEREGION) ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
7994     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7995     flush_events();
7996 
7997     SetRectRgn( hrgn2, rect.left, rect.top, rect.right, rect.bottom );
7998     ok(RedrawWindow(0, NULL, hrgn2, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
7999        "RedrawWindow failed\n");
8000     check_update_rgn( hwnd, hrgn );
8001     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8002     flush_events();
8003     ok_sequence( WmPaint, "Paint", FALSE );
8004     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8005     check_update_rgn( hwnd, 0 );
8006 
8007     ok(RedrawWindow(0, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ERASENOW ),
8008        "RedrawWindow failed\n");
8009     check_update_rgn( hwnd, 0 );
8010 
8011     ok(RedrawWindow(0, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_ERASE | RDW_ERASENOW ),
8012        "RedrawWindow failed\n");
8013     check_update_rgn( hwnd, hrgn );
8014     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8015     flush_events();
8016     ok_sequence( WmPaint, "Paint", FALSE );
8017     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8018     check_update_rgn( hwnd, 0 );
8019 
8020     /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
8021      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
8022      */
8023     SetRectEmpty( &rect );
8024     if (ValidateRect(0, &rect) && /* not supported on Win9x */
8025         GetUpdateRect(hwnd, NULL, FALSE))  /* or >= Win 8 */
8026     {
8027         check_update_rgn( hwnd, hrgn );
8028         ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8029         flush_events();
8030         ok_sequence( WmPaint, "Paint", FALSE );
8031         RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8032         check_update_rgn( hwnd, 0 );
8033     }
8034 
8035     SetLastError(0xdeadbeef);
8036     ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
8037     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef,
8038        "wrong error code %d\n", GetLastError());
8039     check_update_rgn( hwnd, 0 );
8040     flush_events();
8041     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8042 
8043     SetLastError(0xdeadbeef);
8044     ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
8045     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
8046        broken( GetLastError() == 0xdeadbeef ) /* win9x */,
8047        "wrong error code %d\n", GetLastError());
8048     check_update_rgn( hwnd, 0 );
8049     flush_events();
8050     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8051 
8052     SetLastError(0xdeadbeef);
8053     ok(!UpdateWindow(NULL), "UpdateWindow(NULL) should fail\n");
8054     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
8055        broken( GetLastError() == 0xdeadbeef ) /* win9x */,
8056        "wrong error code %d\n", GetLastError());
8057     check_update_rgn( hwnd, 0 );
8058     flush_events();
8059     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8060 
8061     /* now with frame */
8062     SetRectRgn( hrgn, -5, -5, 20, 20 );
8063 
8064     /* flush pending messages */
8065     flush_events();
8066     flush_sequence();
8067     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8068     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
8069 
8070     SetRectRgn( hrgn, 0, 0, 20, 20 );  /* GetUpdateRgn clips to client area */
8071     check_update_rgn( hwnd, hrgn );
8072 
8073     flush_sequence();
8074     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
8075     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
8076 
8077     flush_sequence();
8078     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
8079     ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
8080 
8081     GetClientRect( hwnd, &rect );
8082     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8083     check_update_rgn( hwnd, hrgn );
8084 
8085     flush_sequence();
8086     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
8087     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8088 
8089     flush_sequence();
8090     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
8091     ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
8092     check_update_rgn( hwnd, 0 );
8093 
8094     flush_sequence();
8095     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
8096     ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
8097     check_update_rgn( hwnd, 0 );
8098 
8099     flush_sequence();
8100     SetRectRgn( hrgn, 0, 0, 100, 100 );
8101     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
8102     SetRectRgn( hrgn, 0, 0, 50, 100 );
8103     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
8104     SetRectRgn( hrgn, 50, 0, 100, 100 );
8105     check_update_rgn( hwnd, hrgn );
8106     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
8107     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );  /* must not generate messages, everything is valid */
8108     check_update_rgn( hwnd, 0 );
8109 
8110     flush_sequence();
8111     SetRectRgn( hrgn, 0, 0, 100, 100 );
8112     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
8113     SetRectRgn( hrgn, 0, 0, 100, 50 );
8114     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
8115     ok_sequence( WmErase, "Erase", FALSE );
8116     SetRectRgn( hrgn, 0, 50, 100, 100 );
8117     check_update_rgn( hwnd, hrgn );
8118 
8119     flush_sequence();
8120     SetRectRgn( hrgn, 0, 0, 100, 100 );
8121     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
8122     SetRectRgn( hrgn, 0, 0, 50, 50 );
8123     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
8124     ok_sequence( WmPaint, "Paint", FALSE );
8125 
8126     flush_sequence();
8127     SetRectRgn( hrgn, -4, -4, -2, -2 );
8128     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8129     SetRectRgn( hrgn, -200, -200, -198, -198 );
8130     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
8131     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
8132 
8133     flush_sequence();
8134     SetRectRgn( hrgn, -4, -4, -2, -2 );
8135     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8136     SetRectRgn( hrgn, -4, -4, -3, -3 );
8137     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
8138     SetRectRgn( hrgn, 0, 0, 1, 1 );
8139     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
8140     ok_sequence( WmPaint, "Paint", FALSE );
8141 
8142     flush_sequence();
8143     SetRectRgn( hrgn, -4, -4, -1, -1 );
8144     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8145     RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
8146     /* make sure no WM_PAINT was generated */
8147     flush_events();
8148     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
8149 
8150     flush_sequence();
8151     SetRectRgn( hrgn, -4, -4, -1, -1 );
8152     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8153     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
8154     {
8155         if (msg.hwnd == hwnd && msg.message == WM_PAINT)
8156         {
8157             /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
8158             INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
8159             ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
8160             ret = GetUpdateRect( hwnd, &rect, FALSE );
8161             ok( ret, "Invalid GetUpdateRect result %d\n", ret );
8162             /* this will send WM_NCPAINT and validate the non client area */
8163             ret = GetUpdateRect( hwnd, &rect, TRUE );
8164             ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
8165         }
8166         DispatchMessageA( &msg );
8167     }
8168     ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
8169 
8170     DestroyWindow( hwnd );
8171 
8172     /* now test with a child window */
8173 
8174     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
8175                               100, 100, 200, 200, 0, 0, 0, NULL);
8176     ok (hparent != 0, "Failed to create parent window\n");
8177 
8178     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
8179                            10, 10, 100, 100, hparent, 0, 0, NULL);
8180     ok (hchild != 0, "Failed to create child window\n");
8181 
8182     ShowWindow( hparent, SW_SHOW );
8183     UpdateWindow( hparent );
8184     UpdateWindow( hchild );
8185     flush_events();
8186     flush_sequence();
8187     log_all_parent_messages++;
8188 
8189     SetRect( &rect, 0, 0, 50, 50 );
8190     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8191     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
8192     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
8193 
8194     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8195     pt.x = pt.y = 0;
8196     MapWindowPoints( hchild, hparent, &pt, 1 );
8197     SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
8198     check_update_rgn( hchild, hrgn );
8199     SetRectRgn( hrgn, 0, 0, 50, 50 );
8200     check_update_rgn( hparent, hrgn );
8201     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8202     ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
8203     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
8204     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
8205 
8206     flush_events();
8207     ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
8208 
8209     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
8210     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8211     ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
8212     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
8213     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
8214 
8215     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
8216     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
8217     ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
8218 
8219     SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
8220     flush_sequence();
8221     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
8222     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8223     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
8224 
8225     /* flush all paint messages */
8226     flush_events();
8227     flush_sequence();
8228 
8229     /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
8230     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
8231     SetRectRgn( hrgn, 0, 0, 50, 50 );
8232     check_update_rgn( hparent, hrgn );
8233     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
8234     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8235     SetRectRgn( hrgn, 0, 0, 50, 50 );
8236     check_update_rgn( hparent, hrgn );
8237 
8238     /* flush all paint messages */
8239     flush_events();
8240     SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
8241     flush_sequence();
8242 
8243     /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
8244     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8245     SetRectRgn( hrgn, 0, 0, 50, 50 );
8246     check_update_rgn( hparent, hrgn );
8247     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
8248     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8249     SetRectRgn( hrgn2, 10, 10, 50, 50 );
8250     CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
8251     check_update_rgn( hparent, hrgn );
8252     /* flush all paint messages */
8253     flush_events();
8254     flush_sequence();
8255 
8256     /* same as above but parent gets completely validated */
8257     SetRect( &rect, 20, 20, 30, 30 );
8258     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8259     SetRectRgn( hrgn, 20, 20, 30, 30 );
8260     check_update_rgn( hparent, hrgn );
8261     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
8262     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8263     check_update_rgn( hparent, 0 );  /* no update region */
8264     flush_events();
8265     ok_sequence( WmEmptySeq, "WmEmpty", FALSE );  /* and no paint messages */
8266 
8267     /* make sure RDW_VALIDATE on child doesn't have the same effect */
8268     flush_sequence();
8269     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8270     SetRectRgn( hrgn, 20, 20, 30, 30 );
8271     check_update_rgn( hparent, hrgn );
8272     RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
8273     SetRectRgn( hrgn, 20, 20, 30, 30 );
8274     check_update_rgn( hparent, hrgn );
8275 
8276     /* same as above but normal WM_PAINT doesn't validate parent */
8277     flush_sequence();
8278     SetRect( &rect, 20, 20, 30, 30 );
8279     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8280     SetRectRgn( hrgn, 20, 20, 30, 30 );
8281     check_update_rgn( hparent, hrgn );
8282     /* no WM_PAINT in child while parent still pending */
8283     while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8284     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8285     while (PeekMessageA( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8286     ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
8287 
8288     flush_sequence();
8289     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8290     /* no WM_PAINT in child while parent still pending */
8291     while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8292     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8293     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
8294     /* now that parent is valid child should get WM_PAINT */
8295     while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8296     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8297     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8298     ok_sequence( WmEmptySeq, "No other message", FALSE );
8299 
8300     /* same thing with WS_CLIPCHILDREN in parent */
8301     flush_sequence();
8302     SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
8303     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
8304     /* changing style invalidates non client area, but we need to invalidate something else to see it */
8305     RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
8306     ok_sequence( WmEmptySeq, "No message", FALSE );
8307     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
8308     ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
8309 
8310     flush_sequence();
8311     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
8312     SetRectRgn( hrgn, 20, 20, 30, 30 );
8313     check_update_rgn( hparent, hrgn );
8314     /* no WM_PAINT in child while parent still pending */
8315     while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8316     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8317     /* WM_PAINT in parent first */
8318     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8319     ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
8320 
8321     /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
8322     flush_sequence();
8323     SetRect( &rect, 0, 0, 30, 30 );
8324     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
8325     SetRectRgn( hrgn, 0, 0, 30, 30 );
8326     check_update_rgn( hparent, hrgn );
8327     flush_events();
8328     ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
8329 
8330     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
8331     flush_sequence();
8332     SetRect( &rect, -10, 0, 30, 30 );
8333     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
8334     SetRect( &rect, 0, 0, 20, 20 );
8335     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
8336     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
8337     ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
8338 
8339     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
8340     flush_sequence();
8341     SetRect( &rect, -10, 0, 30, 30 );
8342     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
8343     SetRect( &rect, 0, 0, 100, 100 );
8344     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
8345     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
8346     ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
8347     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8348     ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
8349 
8350     /* WS_CLIPCHILDREN doesn't exclude children from update region */
8351     flush_sequence();
8352     RedrawWindow( hparent, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
8353     GetClientRect( hparent, &rect );
8354     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8355     check_update_rgn( hparent, hrgn );
8356     flush_events();
8357 
8358     RedrawWindow( hparent, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
8359     GetClientRect( hparent, &rect );
8360     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8361     check_update_rgn( hparent, hrgn );
8362     flush_events();
8363 
8364     /* test RDW_INTERNALPAINT behavior */
8365 
8366     flush_sequence();
8367     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
8368     flush_events();
8369     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
8370 
8371     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
8372     flush_events();
8373     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
8374 
8375     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
8376     flush_events();
8377     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
8378 
8379     assert( GetWindowLongA(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
8380     UpdateWindow( hparent );
8381     flush_events();
8382     flush_sequence();
8383     trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
8384     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8385     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
8386                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8387     flush_events();
8388     ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
8389 
8390     UpdateWindow( hparent );
8391     flush_events();
8392     flush_sequence();
8393     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
8394     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8395     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
8396                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8397     flush_events();
8398     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
8399 
8400     SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
8401     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
8402     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
8403     flush_events();
8404     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
8405 
8406     assert( !(GetWindowLongA(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
8407     UpdateWindow( hparent );
8408     flush_events();
8409     flush_sequence();
8410     trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
8411     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8412     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
8413                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8414     flush_events();
8415     ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
8416 
8417     UpdateWindow( hparent );
8418     flush_events();
8419     flush_sequence();
8420     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
8421     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8422     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
8423                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8424     flush_events();
8425     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
8426 
8427     ok(GetWindowLongA( hparent, GWL_STYLE ) & WS_VISIBLE, "parent should be visible\n");
8428     ok(GetWindowLongA( hchild, GWL_STYLE ) & WS_VISIBLE, "child should be visible\n");
8429 
8430     UpdateWindow( hparent );
8431     flush_events();
8432     flush_sequence();
8433     trace("testing SetWindowPos(-10000, -10000) on child\n");
8434     SetWindowPos( hchild, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
8435     check_update_rgn( hchild, 0 );
8436     flush_events();
8437 
8438 #if 0 /* this one doesn't pass under Wine yet */
8439     UpdateWindow( hparent );
8440     flush_events();
8441     flush_sequence();
8442     trace("testing ShowWindow(SW_MINIMIZE) on child\n");
8443     ShowWindow( hchild, SW_MINIMIZE );
8444     check_update_rgn( hchild, 0 );
8445     flush_events();
8446 #endif
8447 
8448     UpdateWindow( hparent );
8449     flush_events();
8450     flush_sequence();
8451     trace("testing SetWindowPos(-10000, -10000) on parent\n");
8452     SetWindowPos( hparent, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
8453     check_update_rgn( hparent, 0 );
8454     flush_events();
8455 
8456     log_all_parent_messages--;
8457     DestroyWindow( hparent );
8458     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
8459 
8460     /* tests for moving windows off-screen (needs simple WS_POPUP windows) */
8461 
8462     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_POPUP | WS_VISIBLE,
8463                               100, 100, 200, 200, 0, 0, 0, NULL);
8464     ok (hparent != 0, "Failed to create parent window\n");
8465 
8466     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
8467                            10, 10, 100, 100, hparent, 0, 0, NULL);
8468     ok (hchild != 0, "Failed to create child window\n");
8469 
8470     ShowWindow( hparent, SW_SHOW );
8471     UpdateWindow( hparent );
8472     UpdateWindow( hchild );
8473     flush_events();
8474     flush_sequence();
8475 
8476     /* moving child outside of parent boundaries changes update region */
8477     SetRect( &rect, 0, 0, 40, 40 );
8478     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
8479     SetRectRgn( hrgn, 0, 0, 40, 40 );
8480     check_update_rgn( hchild, hrgn );
8481     MoveWindow( hchild, -10, 10, 100, 100, FALSE );
8482     SetRectRgn( hrgn, 10, 0, 40, 40 );
8483     check_update_rgn( hchild, hrgn );
8484     MoveWindow( hchild, -10, -10, 100, 100, FALSE );
8485     SetRectRgn( hrgn, 10, 10, 40, 40 );
8486     check_update_rgn( hchild, hrgn );
8487 
8488     /* moving parent off-screen does too */
8489     SetRect( &rect, 0, 0, 100, 100 );
8490     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
8491     SetRectRgn( hrgn, 0, 0, 100, 100 );
8492     check_update_rgn( hparent, hrgn );
8493     SetRectRgn( hrgn, 10, 10, 40, 40 );
8494     check_update_rgn( hchild, hrgn );
8495     MoveWindow( hparent, -20, -20, 200, 200, FALSE );
8496     GetUpdateRect( hparent, &rect2, FALSE );
8497     if (!EqualRect( &rect2, &rect )) /* Win 8 and later don't crop update to screen */
8498     {
8499         rect.left += 20;
8500         rect.top += 20;
8501     }
8502     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8503     check_update_rgn( hparent, hrgn );
8504     SetRectRgn( hrgn, rect.left + 10, rect.top + 10, 40, 40 );
8505     check_update_rgn( hchild, hrgn );
8506 
8507     /* invalidated region is cropped by the parent rects */
8508     SetRect( &rect, 0, 0, 50, 50 );
8509     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
8510     SetRectRgn( hrgn, rect2.left + 10, rect2.top + 10, 50, 50 );
8511     check_update_rgn( hchild, hrgn );
8512 
8513     DestroyWindow( hparent );
8514     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
8515     flush_sequence();
8516 
8517     DeleteObject( hrgn );
8518     DeleteObject( hrgn2 );
8519 }
8520 
8521 struct wnd_event
8522 {
8523     HWND hwnd;
8524     HANDLE grand_child;
8525     HANDLE start_event;
8526     HANDLE stop_event;
8527 };
8528 
8529 static DWORD WINAPI thread_proc(void *param)
8530 {
8531     MSG msg;
8532     struct wnd_event *wnd_event = param;
8533 
8534     wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
8535                                       100, 100, 200, 200, 0, 0, 0, NULL);
8536     ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
8537 
8538     SetEvent(wnd_event->start_event);
8539 
8540     while (GetMessageA(&msg, 0, 0, 0))
8541     {
8542 	TranslateMessage(&msg);
8543 	DispatchMessageA(&msg);
8544     }
8545 
8546     ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
8547 
8548     return 0;
8549 }
8550 
8551 static DWORD CALLBACK create_grand_child_thread( void *param )
8552 {
8553     struct wnd_event *wnd_event = param;
8554     HWND hchild;
8555     MSG msg;
8556 
8557     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
8558                              WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
8559     ok (hchild != 0, "Failed to create child window\n");
8560     flush_events();
8561     flush_sequence();
8562     SetEvent( wnd_event->start_event );
8563 
8564     for (;;)
8565     {
8566         MsgWaitForMultipleObjects(0, NULL, FALSE, 1000, QS_ALLINPUT);
8567         if (!IsWindow( hchild )) break;  /* will be destroyed when parent thread exits */
8568         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8569     }
8570     return 0;
8571 }
8572 
8573 static DWORD CALLBACK create_child_thread( void *param )
8574 {
8575     struct wnd_event *wnd_event = param;
8576     struct wnd_event child_event;
8577     DWORD ret, tid;
8578     MSG msg;
8579 
8580     child_event.hwnd = CreateWindowExA(0, "TestWindowClass", "Test child",
8581                              WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
8582     ok (child_event.hwnd != 0, "Failed to create child window\n");
8583     SetFocus( child_event.hwnd );
8584     flush_events();
8585     flush_sequence();
8586     child_event.start_event = wnd_event->start_event;
8587     wnd_event->grand_child = CreateThread(NULL, 0, create_grand_child_thread, &child_event, 0, &tid);
8588     for (;;)
8589     {
8590         DWORD ret = MsgWaitForMultipleObjects(1, &child_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
8591         if (ret != 1) break;
8592         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8593     }
8594     ret = WaitForSingleObject( wnd_event->stop_event, 5000 );
8595     ok( !ret, "WaitForSingleObject failed %x\n", ret );
8596     return 0;
8597 }
8598 
8599 static const char manifest_dep[] =
8600 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
8601 "<assemblyIdentity version=\"1.2.3.4\"  name=\"testdep1\" type=\"win32\" processorArchitecture=\"" ARCH "\"/>"
8602 "    <file name=\"testdep.dll\" />"
8603 "</assembly>";
8604 
8605 static const char manifest_main[] =
8606 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
8607 "<assemblyIdentity version=\"1.2.3.4\" name=\"Wine.Test\" type=\"win32\" />"
8608 "<dependency>"
8609 " <dependentAssembly>"
8610 "  <assemblyIdentity type=\"win32\" name=\"testdep1\" version=\"1.2.3.4\" processorArchitecture=\"" ARCH "\" />"
8611 " </dependentAssembly>"
8612 "</dependency>"
8613 "</assembly>";
8614 
8615 static void create_manifest_file(const char *filename, const char *manifest)
8616 {
8617     WCHAR path[MAX_PATH];
8618     HANDLE file;
8619     DWORD size;
8620 
8621     MultiByteToWideChar( CP_ACP, 0, filename, -1, path, MAX_PATH );
8622     file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8623     ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
8624     WriteFile(file, manifest, strlen(manifest), &size, NULL);
8625     CloseHandle(file);
8626 }
8627 
8628 static HANDLE test_create(const char *file)
8629 {
8630     WCHAR path[MAX_PATH];
8631     ACTCTXW actctx;
8632     HANDLE handle;
8633 
8634     MultiByteToWideChar(CP_ACP, 0, file, -1, path, MAX_PATH);
8635     memset(&actctx, 0, sizeof(ACTCTXW));
8636     actctx.cbSize = sizeof(ACTCTXW);
8637     actctx.lpSource = path;
8638 
8639     handle = pCreateActCtxW(&actctx);
8640     ok(handle != INVALID_HANDLE_VALUE, "failed to create context, error %u\n", GetLastError());
8641 
8642     ok(actctx.cbSize == sizeof(actctx), "cbSize=%d\n", actctx.cbSize);
8643     ok(actctx.dwFlags == 0, "dwFlags=%d\n", actctx.dwFlags);
8644     ok(actctx.lpSource == path, "lpSource=%p\n", actctx.lpSource);
8645     ok(actctx.wProcessorArchitecture == 0, "wProcessorArchitecture=%d\n", actctx.wProcessorArchitecture);
8646     ok(actctx.wLangId == 0, "wLangId=%d\n", actctx.wLangId);
8647     ok(actctx.lpAssemblyDirectory == NULL, "lpAssemblyDirectory=%p\n", actctx.lpAssemblyDirectory);
8648     ok(actctx.lpResourceName == NULL, "lpResourceName=%p\n", actctx.lpResourceName);
8649     ok(actctx.lpApplicationName == NULL, "lpApplicationName=%p\n", actctx.lpApplicationName);
8650     ok(actctx.hModule == NULL, "hModule=%p\n", actctx.hModule);
8651 
8652     return handle;
8653 }
8654 
8655 static void test_interthread_messages(void)
8656 {
8657     HANDLE hThread, context, handle, event;
8658     ULONG_PTR cookie;
8659     DWORD tid;
8660     WNDPROC proc;
8661     MSG msg;
8662     char buf[256];
8663     int len, expected_len;
8664     struct wnd_event wnd_event;
8665     BOOL ret;
8666 
8667     wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
8668     if (!wnd_event.start_event)
8669     {
8670         win_skip("skipping interthread message test under win9x\n");
8671         return;
8672     }
8673 
8674     hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
8675     ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
8676 
8677     ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8678 
8679     CloseHandle(wnd_event.start_event);
8680 
8681     SetLastError(0xdeadbeef);
8682     ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeeded\n");
8683     ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == 0xdeadbeef,
8684        "wrong error code %d\n", GetLastError());
8685 
8686     proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
8687     ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %d\n", GetLastError());
8688 
8689     expected_len = lstrlenA("window caption text");
8690     memset(buf, 0, sizeof(buf));
8691     SetLastError(0xdeadbeef);
8692     len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
8693     ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %d, len %d, expected len %d\n", GetLastError(), len, expected_len);
8694     ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
8695 
8696     msg.hwnd = wnd_event.hwnd;
8697     msg.message = WM_GETTEXT;
8698     msg.wParam = sizeof(buf);
8699     msg.lParam = (LPARAM)buf;
8700     memset(buf, 0, sizeof(buf));
8701     SetLastError(0xdeadbeef);
8702     len = DispatchMessageA(&msg);
8703     ok((!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY) || broken(len), /* nt4 */
8704        "DispatchMessageA(WM_GETTEXT) succeeded on another thread window: ret %d, error %d\n", len, GetLastError());
8705 
8706     /* the following test causes an exception in user.exe under win9x */
8707     msg.hwnd = wnd_event.hwnd;
8708     msg.message = WM_TIMER;
8709     msg.wParam = 0;
8710     msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
8711     SetLastError(0xdeadbeef);
8712     len = DispatchMessageA(&msg);
8713     ok(!len && GetLastError() == 0xdeadbeef,
8714        "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %d\n", len, GetLastError());
8715 
8716     ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
8717     ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
8718 
8719     ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8720     CloseHandle(hThread);
8721 
8722     ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
8723 
8724     wnd_event.hwnd = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8725                               100, 100, 200, 200, 0, 0, 0, NULL);
8726     ok (wnd_event.hwnd != 0, "Failed to create parent window\n");
8727     flush_events();
8728     flush_sequence();
8729     log_all_parent_messages++;
8730     wnd_event.start_event = CreateEventA( NULL, TRUE, FALSE, NULL );
8731     wnd_event.stop_event = CreateEventA( NULL, TRUE, FALSE, NULL );
8732     hThread = CreateThread( NULL, 0, create_child_thread, &wnd_event, 0, &tid );
8733     for (;;)
8734     {
8735         ret = MsgWaitForMultipleObjects(1, &wnd_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
8736         if (ret != 1) break;
8737         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8738     }
8739     ok( !ret, "MsgWaitForMultipleObjects failed %x\n", ret );
8740     /* now wait for the thread without processing messages; this shouldn't deadlock */
8741     SetEvent( wnd_event.stop_event );
8742     ret = WaitForSingleObject( hThread, 5000 );
8743     ok( !ret, "WaitForSingleObject failed %x\n", ret );
8744     CloseHandle( hThread );
8745 
8746     ret = WaitForSingleObject( wnd_event.grand_child, 5000 );
8747     ok( !ret, "WaitForSingleObject failed %x\n", ret );
8748     CloseHandle( wnd_event.grand_child );
8749 
8750     CloseHandle( wnd_event.start_event );
8751     CloseHandle( wnd_event.stop_event );
8752     flush_events();
8753     ok_sequence(WmExitThreadSeq, "destroy child on thread exit", FALSE);
8754     log_all_parent_messages--;
8755     DestroyWindow( wnd_event.hwnd );
8756 
8757     /* activation context tests */
8758     if (!pActivateActCtx)
8759     {
8760         win_skip("Activation contexts are not supported, skipping\n");
8761         return;
8762     }
8763 
8764     create_manifest_file("testdep1.manifest", manifest_dep);
8765     create_manifest_file("main.manifest", manifest_main);
8766 
8767     context = test_create("main.manifest");
8768     DeleteFileA("testdep1.manifest");
8769     DeleteFileA("main.manifest");
8770 
8771     handle = (void*)0xdeadbeef;
8772     ret = pGetCurrentActCtx(&handle);
8773     ok(ret, "GetCurrentActCtx failed: %u\n", GetLastError());
8774     ok(handle == 0, "active context %p\n", handle);
8775 
8776     wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
8777     hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
8778     ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
8779     ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8780     CloseHandle(wnd_event.start_event);
8781 
8782     /* context is activated after thread creation, so it doesn't inherit it by default */
8783     ret = pActivateActCtx(context, &cookie);
8784     ok(ret, "activation failed: %u\n", GetLastError());
8785 
8786     handle = 0;
8787     ret = pGetCurrentActCtx(&handle);
8788     ok(ret, "GetCurrentActCtx failed: %u\n", GetLastError());
8789     ok(handle != 0, "active context %p\n", handle);
8790     pReleaseActCtx(handle);
8791 
8792     /* destination window will test for active context */
8793     ret = SendMessageA(wnd_event.hwnd, WM_USER+10, 0, 0);
8794     ok(ret, "thread window returned %d\n", ret);
8795 
8796     event = CreateEventW(NULL, 0, 0, NULL);
8797     ret = PostMessageA(wnd_event.hwnd, WM_USER+10, 0, (LPARAM)event);
8798     ok(ret, "thread window returned %d\n", ret);
8799     ok(WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8800     CloseHandle(event);
8801 
8802     ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
8803     ok(ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
8804 
8805     ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8806     CloseHandle(hThread);
8807 
8808     ret = pDeactivateActCtx(0, cookie);
8809     ok(ret, "DeactivateActCtx failed: %u\n", GetLastError());
8810     pReleaseActCtx(context);
8811 }
8812 
8813 
8814 static const struct message WmVkN[] = {
8815     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8816     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8817     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
8818     { WM_CHAR, wparam|lparam, 'n', 1 },
8819     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
8820     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8821     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8822     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8823     { 0 }
8824 };
8825 static const struct message WmShiftVkN[] = {
8826     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
8827     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
8828     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
8829     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8830     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8831     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
8832     { WM_CHAR, wparam|lparam, 'N', 1 },
8833     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
8834     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8835     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8836     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8837     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
8838     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
8839     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
8840     { 0 }
8841 };
8842 static const struct message WmCtrlVkN[] = {
8843     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8844     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8845     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8846     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8847     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8848     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
8849     { WM_CHAR, wparam|lparam, 0x000e, 1 },
8850     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
8851     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8852     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8853     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8854     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8855     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8856     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8857     { 0 }
8858 };
8859 static const struct message WmCtrlVkN_2[] = {
8860     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8861     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8862     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8863     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8864     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8865     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
8866     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8867     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8868     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8869     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8870     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8871     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8872     { 0 }
8873 };
8874 static const struct message WmAltVkN[] = {
8875     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8876     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8877     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8878     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8879     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
8880     { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
8881     { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
8882     { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
8883     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
8884     { HCBT_SYSCOMMAND, hook },
8885     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8886     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8887     { 0x00AE, sent|defwinproc|optional }, /* XP */
8888     { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
8889     { WM_INITMENU, sent|defwinproc },
8890     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8891     { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
8892     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8893     { WM_CAPTURECHANGED, sent|defwinproc },
8894     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
8895     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8896     { WM_EXITMENULOOP, sent|defwinproc },
8897     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
8898     { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
8899     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8900     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
8901     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8902     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8903     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8904     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8905     { 0 }
8906 };
8907 static const struct message WmAltVkN_2[] = {
8908     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8909     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8910     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8911     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8912     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
8913     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
8914     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8915     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
8916     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8917     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8918     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8919     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8920     { 0 }
8921 };
8922 static const struct message WmCtrlAltVkN[] = {
8923     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8924     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8925     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8926     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8927     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8928     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8929     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8930     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
8931     { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
8932     { WM_CHAR, optional },
8933     { WM_CHAR, sent|optional },
8934     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8935     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
8936     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8937     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8938     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8939     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8940     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8941     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8942     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8943     { 0 }
8944 };
8945 static const struct message WmCtrlShiftVkN[] = {
8946     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8947     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8948     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8949     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
8950     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
8951     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
8952     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8953     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8954     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
8955     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8956     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8957     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8958     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
8959     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
8960     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
8961     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8962     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8963     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8964     { 0 }
8965 };
8966 static const struct message WmCtrlAltShiftVkN[] = {
8967     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8968     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8969     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8970     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8971     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8972     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8973     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
8974     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
8975     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
8976     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8977     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
8978     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
8979     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8980     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
8981     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8982     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
8983     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
8984     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
8985     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8986     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8987     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8988     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8989     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8990     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8991     { 0 }
8992 };
8993 static const struct message WmAltPressRelease[] = {
8994     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8995     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8996     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8997     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8998     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8999     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
9000     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
9001     { HCBT_SYSCOMMAND, hook },
9002     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
9003     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
9004     { WM_INITMENU, sent|defwinproc },
9005     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
9006     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
9007     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
9008 
9009     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
9010 
9011     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
9012     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
9013     { WM_CAPTURECHANGED, sent|defwinproc },
9014     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
9015     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
9016     { WM_EXITMENULOOP, sent|defwinproc },
9017     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
9018     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
9019     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
9020     { 0 }
9021 };
9022 static const struct message WmShiftMouseButton[] = {
9023     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
9024     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
9025     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
9026     { WM_MOUSEMOVE, wparam|optional, 0, 0 },
9027     { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
9028     { WM_LBUTTONDOWN, wparam, MK_LBUTTON|MK_SHIFT, 0 },
9029     { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON|MK_SHIFT, 0 },
9030     { WM_LBUTTONUP, wparam, MK_SHIFT, 0 },
9031     { WM_LBUTTONUP, sent|wparam, MK_SHIFT, 0 },
9032     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
9033     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
9034     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
9035     { 0 }
9036 };
9037 static const struct message WmF1Seq[] = {
9038     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
9039     { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
9040     { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
9041     { WM_KEYF1, wparam|lparam, 0, 0 },
9042     { WM_KEYF1, sent|wparam|lparam, 0, 0 },
9043     { WM_HELP, sent|defwinproc },
9044     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
9045     { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
9046     { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
9047     { 0 }
9048 };
9049 static const struct message WmVkAppsSeq[] = {
9050     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
9051     { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
9052     { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
9053     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
9054     { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
9055     { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
9056     { WM_CONTEXTMENU, lparam, /*hwnd*/0, -1 },
9057     { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, -1 },
9058     { 0 }
9059 };
9060 static const struct message WmVkF10Seq[] = {
9061     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
9062     { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
9063     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
9064     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
9065     { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
9066     { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
9067     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
9068     { HCBT_SYSCOMMAND, hook },
9069     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
9070     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
9071     { WM_INITMENU, sent|defwinproc },
9072     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
9073     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
9074     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
9075 
9076     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0x10000001 }, /* XP */
9077 
9078     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
9079     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
9080     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
9081     { WM_CAPTURECHANGED, sent|defwinproc },
9082     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
9083     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
9084     { WM_EXITMENULOOP, sent|defwinproc },
9085     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
9086     { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
9087     { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
9088     { 0 }
9089 };
9090 static const struct message WmShiftF10Seq[] = {
9091     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
9092     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
9093     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x00000001 },
9094     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
9095     { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
9096     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
9097     { WM_CONTEXTMENU, sent|defwinproc|lparam, /*hwnd*/0, -1 },
9098     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
9099     { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
9100     { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
9101     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
9102     { HCBT_SYSCOMMAND, hook },
9103     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
9104     { WM_INITMENU, sent|defwinproc },
9105     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
9106     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xd0000001 }, /* XP */
9107     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0x10000001 }, /* XP */
9108     { WM_CAPTURECHANGED, sent|defwinproc|wparam|lparam, 0, 0 },
9109     { WM_MENUSELECT, sent|defwinproc|wparam|lparam, 0xffff0000, 0 },
9110     { WM_EXITMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
9111     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 }, /* XP */
9112     { WM_KEYUP, wparam|lparam, VK_ESCAPE, 0xc0000001 },
9113     { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
9114     { 0 }
9115 };
9116 
9117 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
9118 {
9119     MSG msg;
9120 
9121     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
9122     {
9123         struct recvd_message log_msg;
9124 
9125         /* ignore some unwanted messages */
9126         if (msg.message == WM_MOUSEMOVE ||
9127             msg.message == WM_TIMER ||
9128             ignore_message( msg.message ))
9129             continue;
9130 
9131         log_msg.hwnd = msg.hwnd;
9132         log_msg.message = msg.message;
9133         log_msg.flags = wparam|lparam;
9134         log_msg.wParam = msg.wParam;
9135         log_msg.lParam = msg.lParam;
9136         log_msg.descr = "accel";
9137         add_message(&log_msg);
9138 
9139         if (!hAccel || !TranslateAcceleratorA(hwnd, hAccel, &msg))
9140         {
9141             TranslateMessage(&msg);
9142             DispatchMessageA(&msg);
9143         }
9144     }
9145 }
9146 
9147 static void test_accelerators(void)
9148 {
9149     RECT rc;
9150     POINT pt;
9151     SHORT state;
9152     HACCEL hAccel;
9153     HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9154                                 100, 100, 200, 200, 0, 0, 0, NULL);
9155     BOOL ret;
9156 
9157     assert(hwnd != 0);
9158     UpdateWindow(hwnd);
9159     flush_events();
9160     flush_sequence();
9161 
9162     SetFocus(hwnd);
9163     ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
9164 
9165     state = GetKeyState(VK_SHIFT);
9166     ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
9167     state = GetKeyState(VK_CAPITAL);
9168     ok(state == 0, "wrong CapsLock state %04x\n", state);
9169 
9170     hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
9171     assert(hAccel != 0);
9172 
9173     flush_events();
9174     pump_msg_loop(hwnd, 0);
9175     flush_sequence();
9176 
9177     trace("testing VK_N press/release\n");
9178     flush_sequence();
9179     keybd_event('N', 0, 0, 0);
9180     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9181     pump_msg_loop(hwnd, hAccel);
9182     if (!sequence_cnt)  /* we didn't get any message */
9183     {
9184         skip( "queuing key events not supported\n" );
9185         goto done;
9186     }
9187     ok_sequence(WmVkN, "VK_N press/release", FALSE);
9188 
9189     trace("testing Shift+VK_N press/release\n");
9190     flush_sequence();
9191     keybd_event(VK_SHIFT, 0, 0, 0);
9192     keybd_event('N', 0, 0, 0);
9193     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9194     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9195     pump_msg_loop(hwnd, hAccel);
9196     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
9197 
9198     trace("testing Ctrl+VK_N press/release\n");
9199     flush_sequence();
9200     keybd_event(VK_CONTROL, 0, 0, 0);
9201     keybd_event('N', 0, 0, 0);
9202     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9203     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9204     pump_msg_loop(hwnd, hAccel);
9205     ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
9206 
9207     trace("testing Alt+VK_N press/release\n");
9208     flush_sequence();
9209     keybd_event(VK_MENU, 0, 0, 0);
9210     keybd_event('N', 0, 0, 0);
9211     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9212     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9213     pump_msg_loop(hwnd, hAccel);
9214     ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
9215 
9216     trace("testing Ctrl+Alt+VK_N press/release 1\n");
9217     flush_sequence();
9218     keybd_event(VK_CONTROL, 0, 0, 0);
9219     keybd_event(VK_MENU, 0, 0, 0);
9220     keybd_event('N', 0, 0, 0);
9221     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9222     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9223     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9224     pump_msg_loop(hwnd, hAccel);
9225     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
9226 
9227     ret = DestroyAcceleratorTable(hAccel);
9228     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
9229 
9230     hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(2));
9231     assert(hAccel != 0);
9232 
9233     trace("testing VK_N press/release\n");
9234     flush_sequence();
9235     keybd_event('N', 0, 0, 0);
9236     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9237     pump_msg_loop(hwnd, hAccel);
9238     ok_sequence(WmVkN, "VK_N press/release", FALSE);
9239 
9240     trace("testing Shift+VK_N press/release\n");
9241     flush_sequence();
9242     keybd_event(VK_SHIFT, 0, 0, 0);
9243     keybd_event('N', 0, 0, 0);
9244     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9245     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9246     pump_msg_loop(hwnd, hAccel);
9247     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
9248 
9249     trace("testing Ctrl+VK_N press/release 2\n");
9250     flush_sequence();
9251     keybd_event(VK_CONTROL, 0, 0, 0);
9252     keybd_event('N', 0, 0, 0);
9253     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9254     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9255     pump_msg_loop(hwnd, hAccel);
9256     ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
9257 
9258     trace("testing Alt+VK_N press/release 2\n");
9259     flush_sequence();
9260     keybd_event(VK_MENU, 0, 0, 0);
9261     keybd_event('N', 0, 0, 0);
9262     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9263     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9264     pump_msg_loop(hwnd, hAccel);
9265     ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
9266 
9267     trace("testing Ctrl+Alt+VK_N press/release 2\n");
9268     flush_sequence();
9269     keybd_event(VK_CONTROL, 0, 0, 0);
9270     keybd_event(VK_MENU, 0, 0, 0);
9271     keybd_event('N', 0, 0, 0);
9272     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9273     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9274     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9275     pump_msg_loop(hwnd, hAccel);
9276     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
9277 
9278     trace("testing Ctrl+Shift+VK_N press/release\n");
9279     flush_sequence();
9280     keybd_event(VK_CONTROL, 0, 0, 0);
9281     keybd_event(VK_SHIFT, 0, 0, 0);
9282     keybd_event('N', 0, 0, 0);
9283     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9284     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9285     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9286     pump_msg_loop(hwnd, hAccel);
9287     ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
9288 
9289     trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
9290     flush_sequence();
9291     keybd_event(VK_CONTROL, 0, 0, 0);
9292     keybd_event(VK_MENU, 0, 0, 0);
9293     keybd_event(VK_SHIFT, 0, 0, 0);
9294     keybd_event('N', 0, 0, 0);
9295     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9296     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9297     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9298     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9299     pump_msg_loop(hwnd, hAccel);
9300     ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
9301 
9302     ret = DestroyAcceleratorTable(hAccel);
9303     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
9304     hAccel = 0;
9305 
9306     trace("testing Alt press/release\n");
9307     flush_sequence();
9308     keybd_event(VK_MENU, 0, 0, 0);
9309     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9310     keybd_event(VK_MENU, 0, 0, 0);
9311     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9312     pump_msg_loop(hwnd, 0);
9313     /* this test doesn't pass in Wine for managed windows */
9314     ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
9315 
9316     trace("testing VK_F1 press/release\n");
9317     keybd_event(VK_F1, 0, 0, 0);
9318     keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
9319     pump_msg_loop(hwnd, 0);
9320     ok_sequence(WmF1Seq, "F1 press/release", FALSE);
9321 
9322     trace("testing VK_APPS press/release\n");
9323     keybd_event(VK_APPS, 0, 0, 0);
9324     keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
9325     pump_msg_loop(hwnd, 0);
9326     ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
9327 
9328     trace("testing VK_F10 press/release\n");
9329     keybd_event(VK_F10, 0, 0, 0);
9330     keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
9331     keybd_event(VK_F10, 0, 0, 0);
9332     keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
9333     pump_msg_loop(hwnd, 0);
9334     ok_sequence(WmVkF10Seq, "VK_F10 press/release", TRUE);
9335 
9336     trace("testing SHIFT+F10 press/release\n");
9337     keybd_event(VK_SHIFT, 0, 0, 0);
9338     keybd_event(VK_F10, 0, 0, 0);
9339     keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
9340     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9341     keybd_event(VK_ESCAPE, 0, 0, 0);
9342     keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
9343     pump_msg_loop(hwnd, 0);
9344     ok_sequence(WmShiftF10Seq, "SHIFT+F10 press/release", TRUE);
9345 
9346     trace("testing Shift+MouseButton press/release\n");
9347     /* first, move mouse pointer inside of the window client area */
9348     GetClientRect(hwnd, &rc);
9349     MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
9350     rc.left += (rc.right - rc.left)/2;
9351     rc.top += (rc.bottom - rc.top)/2;
9352     SetCursorPos(rc.left, rc.top);
9353     SetActiveWindow(hwnd);
9354 
9355     flush_events();
9356     flush_sequence();
9357     GetCursorPos(&pt);
9358     if (pt.x == rc.left && pt.y == rc.top)
9359     {
9360         int i;
9361         keybd_event(VK_SHIFT, 0, 0, 0);
9362         mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
9363         mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
9364         keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9365         pump_msg_loop(hwnd, 0);
9366         for (i = 0; i < sequence_cnt; i++) if (sequence[i].message == WM_LBUTTONDOWN) break;
9367         if (i < sequence_cnt)
9368             ok_sequence(WmShiftMouseButton, "Shift+MouseButton press/release", FALSE);
9369         else
9370             skip( "Shift+MouseButton event didn't get to the window\n" );
9371     }
9372 
9373 done:
9374     if (hAccel) DestroyAcceleratorTable(hAccel);
9375     DestroyWindow(hwnd);
9376 }
9377 
9378 /************* window procedures ********************/
9379 
9380 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message,
9381 			     WPARAM wParam, LPARAM lParam)
9382 {
9383     static LONG defwndproc_counter = 0;
9384     static LONG beginpaint_counter = 0;
9385     LRESULT ret;
9386     struct recvd_message msg;
9387 
9388     if (ignore_message( message )) return 0;
9389 
9390     switch (message)
9391     {
9392 	case WM_ENABLE:
9393 	{
9394 	    LONG style = GetWindowLongA(hwnd, GWL_STYLE);
9395 	    ok((BOOL)wParam == !(style & WS_DISABLED),
9396 		"wrong WS_DISABLED state: %ld != %d\n", wParam, !(style & WS_DISABLED));
9397 	    break;
9398 	}
9399 
9400 	case WM_CAPTURECHANGED:
9401 	    if (test_DestroyWindow_flag)
9402 	    {
9403 		DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
9404 		if (style & WS_CHILD)
9405 		    lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
9406 		else if (style & WS_POPUP)
9407 		    lParam = WND_POPUP_ID;
9408 		else
9409 		    lParam = WND_PARENT_ID;
9410 	    }
9411 	    break;
9412 
9413 	case WM_NCDESTROY:
9414 	{
9415 	    HWND capture;
9416 
9417 	    ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
9418 	    capture = GetCapture();
9419 	    if (capture)
9420 	    {
9421 		ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
9422 		trace("current capture %p, releasing...\n", capture);
9423 		ReleaseCapture();
9424 	    }
9425 	}
9426 	/* fall through */
9427 	case WM_DESTROY:
9428             if (pGetAncestor)
9429 	        ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
9430 	    if (test_DestroyWindow_flag)
9431 	    {
9432 		DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
9433 		if (style & WS_CHILD)
9434 		    lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
9435 		else if (style & WS_POPUP)
9436 		    lParam = WND_POPUP_ID;
9437 		else
9438 		    lParam = WND_PARENT_ID;
9439 	    }
9440 	    break;
9441 
9442 	/* test_accelerators() depends on this */
9443 	case WM_NCHITTEST:
9444 	    return HTCLIENT;
9445 
9446 	case WM_USER+10:
9447 	{
9448 	    ACTIVATION_CONTEXT_BASIC_INFORMATION basicinfo;
9449 	    HANDLE handle, event = (HANDLE)lParam;
9450 	    BOOL ret;
9451 
9452 	    handle = (void*)0xdeadbeef;
9453 	    ret = pGetCurrentActCtx(&handle);
9454 	    ok(ret, "failed to get current context, %u\n", GetLastError());
9455 	    ok(handle == 0, "got active context %p\n", handle);
9456 
9457 	    memset(&basicinfo, 0xff, sizeof(basicinfo));
9458 	    ret = pQueryActCtxW(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX, handle, 0, ActivationContextBasicInformation,
9459 	        &basicinfo, sizeof(basicinfo), NULL);
9460 	    ok(ret, "got %d, error %d\n", ret, GetLastError());
9461 	    ok(basicinfo.hActCtx == NULL, "got %p\n", basicinfo.hActCtx);
9462 	    ok(basicinfo.dwFlags == 0, "got %x\n", basicinfo.dwFlags);
9463 
9464 	    if (event) SetEvent(event);
9465 	    return 1;
9466 	}
9467 
9468 	/* ignore */
9469 	case WM_MOUSEMOVE:
9470 	case WM_MOUSEACTIVATE:
9471 	case WM_NCMOUSEMOVE:
9472 	case WM_SETCURSOR:
9473 	case WM_IME_SELECT:
9474 	    return 0;
9475     }
9476 
9477     msg.hwnd = hwnd;
9478     msg.message = message;
9479     msg.flags = sent|wparam|lparam;
9480     if (defwndproc_counter) msg.flags |= defwinproc;
9481     if (beginpaint_counter) msg.flags |= beginpaint;
9482     msg.wParam = wParam;
9483     msg.lParam = lParam;
9484     msg.descr = "MsgCheckProc";
9485     add_message(&msg);
9486 
9487     if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
9488     {
9489 	HWND parent = GetParent(hwnd);
9490 	RECT rc;
9491 	MINMAXINFO *minmax = (MINMAXINFO *)lParam;
9492 
9493 	GetClientRect(parent, &rc);
9494 	trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
9495         trace("Reserved=%d,%d MaxSize=%d,%d MaxPos=%d,%d MinTrack=%d,%d MaxTrack=%d,%d\n",
9496               minmax->ptReserved.x, minmax->ptReserved.y,
9497               minmax->ptMaxSize.x, minmax->ptMaxSize.y,
9498               minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
9499               minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
9500               minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
9501 
9502 	ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n",
9503 	   minmax->ptMaxSize.x, rc.right);
9504 	ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %d != %d\n",
9505 	   minmax->ptMaxSize.y, rc.bottom);
9506     }
9507 
9508     if (message == WM_PAINT)
9509     {
9510         PAINTSTRUCT ps;
9511         beginpaint_counter++;
9512         BeginPaint( hwnd, &ps );
9513         beginpaint_counter--;
9514         EndPaint( hwnd, &ps );
9515         return 0;
9516     }
9517 
9518     if (!test_context_menu && message == WM_CONTEXTMENU)
9519     {
9520         /* don't create context menu */
9521         return 0;
9522     }
9523 
9524     defwndproc_counter++;
9525     ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam)
9526 		  : DefWindowProcA(hwnd, message, wParam, lParam);
9527     defwndproc_counter--;
9528 
9529     return ret;
9530 }
9531 
9532 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9533 {
9534     return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
9535 }
9536 
9537 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9538 {
9539     return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
9540 }
9541 
9542 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9543 {
9544     static LONG defwndproc_counter = 0;
9545     LRESULT ret;
9546     struct recvd_message msg;
9547 
9548     if (ignore_message( message )) return 0;
9549 
9550     switch (message)
9551     {
9552     case WM_QUERYENDSESSION:
9553     case WM_ENDSESSION:
9554         lParam &= ~0x01;  /* Vista adds a 0x01 flag */
9555         break;
9556     }
9557 
9558     msg.hwnd = hwnd;
9559     msg.message = message;
9560     msg.flags = sent|wparam|lparam;
9561     if (defwndproc_counter) msg.flags |= defwinproc;
9562     msg.wParam = wParam;
9563     msg.lParam = lParam;
9564     msg.descr = "popup";
9565     add_message(&msg);
9566 
9567     if (message == WM_CREATE)
9568     {
9569 	DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
9570 	SetWindowLongA(hwnd, GWL_STYLE, style);
9571     }
9572 
9573     defwndproc_counter++;
9574     ret = DefWindowProcA(hwnd, message, wParam, lParam);
9575     defwndproc_counter--;
9576 
9577     return ret;
9578 }
9579 
9580 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9581 {
9582     static LONG defwndproc_counter = 0;
9583     static LONG beginpaint_counter = 0;
9584     LRESULT ret;
9585     struct recvd_message msg;
9586 
9587     if (ignore_message( message )) return 0;
9588 
9589     if (log_all_parent_messages ||
9590         message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
9591 	message == WM_SETFOCUS || message == WM_KILLFOCUS ||
9592 	message == WM_ENABLE ||	message == WM_ENTERIDLE ||
9593 	message == WM_DRAWITEM || message == WM_MEASUREITEM || message == WM_COMPAREITEM ||
9594 	message == WM_COMMAND || message == WM_IME_SETCONTEXT)
9595     {
9596         switch (message)
9597         {
9598             /* ignore */
9599             case WM_NCHITTEST:
9600                 return HTCLIENT;
9601             case WM_SETCURSOR:
9602             case WM_MOUSEMOVE:
9603             case WM_NCMOUSEMOVE:
9604                 return 0;
9605 
9606             case WM_ERASEBKGND:
9607             {
9608                 RECT rc;
9609                 INT ret = GetClipBox((HDC)wParam, &rc);
9610 
9611                 trace("WM_ERASEBKGND: GetClipBox()=%d, %s\n", ret, wine_dbgstr_rect(&rc));
9612                 break;
9613             }
9614         }
9615 
9616         msg.hwnd = hwnd;
9617         msg.message = message;
9618         msg.flags = sent|parent|wparam|lparam;
9619         if (defwndproc_counter) msg.flags |= defwinproc;
9620         if (beginpaint_counter) msg.flags |= beginpaint;
9621         msg.wParam = wParam;
9622         msg.lParam = lParam;
9623         msg.descr = "parent";
9624         add_message(&msg);
9625     }
9626 
9627     if (message == WM_PAINT)
9628     {
9629         PAINTSTRUCT ps;
9630         beginpaint_counter++;
9631         BeginPaint( hwnd, &ps );
9632         beginpaint_counter--;
9633         EndPaint( hwnd, &ps );
9634         return 0;
9635     }
9636 
9637     defwndproc_counter++;
9638     ret = DefWindowProcA(hwnd, message, wParam, lParam);
9639     defwndproc_counter--;
9640 
9641     return message == WM_COMPAREITEM ? -1 : ret;
9642 }
9643 
9644 static INT_PTR CALLBACK StopQuitMsgCheckProcA(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
9645 {
9646     if (message == WM_CREATE)
9647         PostMessageA(hwnd, WM_CLOSE, 0, 0);
9648     else if (message == WM_CLOSE)
9649     {
9650         /* Only the first WM_QUIT will survive the window destruction */
9651         PostMessageA(hwnd, WM_USER, 0x1234, 0x5678);
9652         PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
9653         PostMessageA(hwnd, WM_QUIT, 0x4321, 0x8765);
9654     }
9655 
9656     return DefWindowProcA(hwnd, message, wp, lp);
9657 }
9658 
9659 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9660 {
9661     static LONG defwndproc_counter = 0;
9662     LRESULT ret;
9663     struct recvd_message msg;
9664 
9665     if (ignore_message( message )) return 0;
9666 
9667     if (test_def_id)
9668     {
9669         DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
9670         ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
9671         if (after_end_dialog)
9672             ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
9673         else
9674             ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
9675     }
9676 
9677     msg.hwnd = hwnd;
9678     msg.message = message;
9679     msg.flags = sent|wparam|lparam;
9680     if (defwndproc_counter) msg.flags |= defwinproc;
9681     msg.wParam = wParam;
9682     msg.lParam = lParam;
9683     msg.descr = "dialog";
9684     add_message(&msg);
9685 
9686     defwndproc_counter++;
9687     ret = DefDlgProcA(hwnd, message, wParam, lParam);
9688     defwndproc_counter--;
9689 
9690     return ret;
9691 }
9692 
9693 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9694 {
9695     static LONG defwndproc_counter = 0;
9696     LRESULT ret;
9697     struct recvd_message msg;
9698 
9699     /* log only specific messages we are interested in */
9700     switch (message)
9701     {
9702 #if 0 /* probably log these as well */
9703     case WM_ACTIVATE:
9704     case WM_SETFOCUS:
9705     case WM_KILLFOCUS:
9706 #endif
9707     case WM_SHOWWINDOW:
9708     case WM_SIZE:
9709     case WM_MOVE:
9710     case WM_GETMINMAXINFO:
9711     case WM_WINDOWPOSCHANGING:
9712     case WM_WINDOWPOSCHANGED:
9713         break;
9714 
9715     default: /* ignore */
9716         /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
9717         return DefWindowProcA(hwnd, message, wParam, lParam);
9718     }
9719 
9720     msg.hwnd = hwnd;
9721     msg.message = message;
9722     msg.flags = sent|wparam|lparam;
9723     if (defwndproc_counter) msg.flags |= defwinproc;
9724     msg.wParam = wParam;
9725     msg.lParam = lParam;
9726     msg.descr = "show";
9727     add_message(&msg);
9728 
9729     defwndproc_counter++;
9730     ret = DefWindowProcA(hwnd, message, wParam, lParam);
9731     defwndproc_counter--;
9732 
9733     return ret;
9734 }
9735 
9736 static LRESULT WINAPI recursive_activation_wndprocA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9737 {
9738     static LONG defwndproc_counter = 0;
9739     struct recvd_message msg;
9740     LRESULT ret;
9741 
9742     switch (message)
9743     {
9744     /* log only specific messages we are interested in */
9745     case WM_NCACTIVATE:
9746     case WM_ACTIVATE:
9747     case WM_SETFOCUS:
9748     case WM_KILLFOCUS:
9749         break;
9750     default:
9751         return DefWindowProcA(hwnd, message, wParam, lParam);
9752     }
9753 
9754     msg.hwnd = hwnd;
9755     msg.message = message;
9756     msg.flags = sent|wparam|lparam;
9757     if (defwndproc_counter) msg.flags |= defwinproc;
9758     msg.wParam = wParam;
9759     msg.lParam = lParam;
9760     msg.descr = "recursive_activation";
9761     add_message(&msg);
9762 
9763     /* recursively activate ourselves by first losing activation and changing it back */
9764     if (message == WM_ACTIVATE && LOWORD(wParam) != WA_INACTIVE)
9765     {
9766         SetActiveWindow((HWND)lParam);
9767         SetActiveWindow(hwnd);
9768         return 0;
9769     }
9770 
9771     defwndproc_counter++;
9772     ret = DefWindowProcA(hwnd, message, wParam, lParam);
9773     defwndproc_counter--;
9774 
9775     return ret;
9776 }
9777 
9778 static LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
9779 {
9780     switch (msg)
9781     {
9782         case WM_CREATE: return 0;
9783         case WM_PAINT:
9784         {
9785             MSG msg2;
9786             static int i = 0;
9787 
9788             if (i < 256)
9789             {
9790                 i++;
9791                 if (PeekMessageA(&msg2, 0, 0, 0, 1))
9792                 {
9793                     TranslateMessage(&msg2);
9794                     DispatchMessageA(&msg2);
9795                 }
9796                 i--;
9797             }
9798             else ok(broken(1), "infinite loop\n");
9799             if ( i == 0)
9800                 paint_loop_done = TRUE;
9801             return DefWindowProcA(hWnd,msg,wParam,lParam);
9802         }
9803     }
9804     return DefWindowProcA(hWnd,msg,wParam,lParam);
9805 }
9806 
9807 static LRESULT WINAPI HotkeyMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9808 {
9809     static LONG defwndproc_counter = 0;
9810     LRESULT ret;
9811     struct recvd_message msg;
9812     DWORD queue_status;
9813 
9814     if (ignore_message( message )) return 0;
9815 
9816     if ((message >= WM_KEYFIRST && message <= WM_KEYLAST) ||
9817         message == WM_HOTKEY || message >= WM_APP)
9818     {
9819         msg.hwnd = hwnd;
9820         msg.message = message;
9821         msg.flags = sent|wparam|lparam;
9822         if (defwndproc_counter) msg.flags |= defwinproc;
9823         msg.wParam = wParam;
9824         msg.lParam = lParam;
9825         msg.descr = "HotkeyMsgCheckProcA";
9826         add_message(&msg);
9827     }
9828 
9829     defwndproc_counter++;
9830     ret = DefWindowProcA(hwnd, message, wParam, lParam);
9831     defwndproc_counter--;
9832 
9833     if (message == WM_APP)
9834     {
9835         queue_status = GetQueueStatus(QS_HOTKEY);
9836         ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
9837         queue_status = GetQueueStatus(QS_POSTMESSAGE);
9838         ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
9839         PostMessageA(hwnd, WM_APP+1, 0, 0);
9840     }
9841     else if (message == WM_APP+1)
9842     {
9843         queue_status = GetQueueStatus(QS_HOTKEY);
9844         ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
9845     }
9846 
9847     return ret;
9848 }
9849 
9850 static BOOL RegisterWindowClasses(void)
9851 {
9852     WNDCLASSA cls;
9853     WNDCLASSW clsW;
9854 
9855     cls.style = 0;
9856     cls.lpfnWndProc = MsgCheckProcA;
9857     cls.cbClsExtra = 0;
9858     cls.cbWndExtra = 0;
9859     cls.hInstance = GetModuleHandleA(0);
9860     cls.hIcon = 0;
9861     cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
9862     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
9863     cls.lpszMenuName = NULL;
9864     cls.lpszClassName = "TestWindowClass";
9865     if(!RegisterClassA(&cls)) return FALSE;
9866 
9867     cls.lpfnWndProc = HotkeyMsgCheckProcA;
9868     cls.lpszClassName = "HotkeyWindowClass";
9869     if(!RegisterClassA(&cls)) return FALSE;
9870 
9871     cls.lpfnWndProc = ShowWindowProcA;
9872     cls.lpszClassName = "ShowWindowClass";
9873     if(!RegisterClassA(&cls)) return FALSE;
9874 
9875     cls.lpfnWndProc = recursive_activation_wndprocA;
9876     cls.lpszClassName = "RecursiveActivationClass";
9877     if(!RegisterClassA(&cls)) return FALSE;
9878 
9879     cls.lpfnWndProc = PopupMsgCheckProcA;
9880     cls.lpszClassName = "TestPopupClass";
9881     if(!RegisterClassA(&cls)) return FALSE;
9882 
9883     cls.lpfnWndProc = ParentMsgCheckProcA;
9884     cls.lpszClassName = "TestParentClass";
9885     if(!RegisterClassA(&cls)) return FALSE;
9886 
9887     cls.lpfnWndProc = StopQuitMsgCheckProcA;
9888     cls.lpszClassName = "StopQuitClass";
9889     if(!RegisterClassA(&cls)) return FALSE;
9890 
9891     cls.lpfnWndProc = DefWindowProcA;
9892     cls.lpszClassName = "SimpleWindowClass";
9893     if(!RegisterClassA(&cls)) return FALSE;
9894 
9895     cls.lpfnWndProc = PaintLoopProcA;
9896     cls.lpszClassName = "PaintLoopWindowClass";
9897     if(!RegisterClassA(&cls)) return FALSE;
9898 
9899     cls.style = CS_NOCLOSE;
9900     cls.lpszClassName = "NoCloseWindowClass";
9901     if(!RegisterClassA(&cls)) return FALSE;
9902 
9903     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
9904     cls.style = 0;
9905     cls.hInstance = GetModuleHandleA(0);
9906     cls.hbrBackground = 0;
9907     cls.lpfnWndProc = TestDlgProcA;
9908     cls.lpszClassName = "TestDialogClass";
9909     if(!RegisterClassA(&cls)) return FALSE;
9910 
9911     clsW.style = 0;
9912     clsW.lpfnWndProc = MsgCheckProcW;
9913     clsW.cbClsExtra = 0;
9914     clsW.cbWndExtra = 0;
9915     clsW.hInstance = GetModuleHandleW(0);
9916     clsW.hIcon = 0;
9917     clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
9918     clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
9919     clsW.lpszMenuName = NULL;
9920     clsW.lpszClassName = testWindowClassW;
9921     RegisterClassW(&clsW);  /* ignore error, this fails on Win9x */
9922 
9923     return TRUE;
9924 }
9925 
9926 static BOOL is_our_logged_class(HWND hwnd)
9927 {
9928     char buf[256];
9929 
9930     if (GetClassNameA(hwnd, buf, sizeof(buf)))
9931     {
9932 	if (!lstrcmpiA(buf, "TestWindowClass") ||
9933 	    !lstrcmpiA(buf, "ShowWindowClass") ||
9934 	    !lstrcmpiA(buf, "RecursiveActivationClass") ||
9935 	    !lstrcmpiA(buf, "TestParentClass") ||
9936 	    !lstrcmpiA(buf, "TestPopupClass") ||
9937 	    !lstrcmpiA(buf, "SimpleWindowClass") ||
9938 	    !lstrcmpiA(buf, "TestDialogClass") ||
9939 	    !lstrcmpiA(buf, "MDI_frame_class") ||
9940 	    !lstrcmpiA(buf, "MDI_client_class") ||
9941 	    !lstrcmpiA(buf, "MDI_child_class") ||
9942 	    !lstrcmpiA(buf, "my_button_class") ||
9943 	    !lstrcmpiA(buf, "my_edit_class") ||
9944 	    !lstrcmpiA(buf, "static") ||
9945 	    !lstrcmpiA(buf, "ListBox") ||
9946 	    !lstrcmpiA(buf, "ComboBox") ||
9947 	    !lstrcmpiA(buf, "MyDialogClass") ||
9948 	    !lstrcmpiA(buf, "#32770") ||
9949 	    !lstrcmpiA(buf, "#32768"))
9950         return TRUE;
9951     }
9952     return FALSE;
9953 }
9954 
9955 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
9956 {
9957     HWND hwnd;
9958 
9959     ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
9960 
9961     if (nCode == HCBT_CLICKSKIPPED)
9962     {
9963         /* ignore this event, XP sends it a lot when switching focus between windows */
9964 	return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
9965     }
9966 
9967     if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
9968     {
9969 	struct recvd_message msg;
9970 
9971         msg.hwnd = 0;
9972 	msg.message = nCode;
9973 	msg.flags = hook|wparam|lparam;
9974 	msg.wParam = wParam;
9975 	msg.lParam = lParam;
9976         msg.descr = "CBT";
9977 	add_message(&msg);
9978 
9979 	return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
9980     }
9981 
9982     if (nCode == HCBT_DESTROYWND)
9983     {
9984 	if (test_DestroyWindow_flag)
9985 	{
9986 	    DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
9987 	    if (style & WS_CHILD)
9988 		lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
9989 	    else if (style & WS_POPUP)
9990 		lParam = WND_POPUP_ID;
9991 	    else
9992 		lParam = WND_PARENT_ID;
9993 	}
9994     }
9995 
9996     /* Log also SetFocus(0) calls */
9997     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
9998 
9999     if (is_our_logged_class(hwnd))
10000     {
10001         struct recvd_message msg;
10002 
10003         msg.hwnd = hwnd;
10004         msg.message = nCode;
10005         msg.flags = hook|wparam|lparam;
10006         msg.wParam = wParam;
10007         msg.lParam = lParam;
10008         msg.descr = "CBT";
10009         add_message(&msg);
10010     }
10011     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
10012 }
10013 
10014 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
10015 				    DWORD event,
10016 				    HWND hwnd,
10017 				    LONG object_id,
10018 				    LONG child_id,
10019 				    DWORD thread_id,
10020 				    DWORD event_time)
10021 {
10022     ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
10023 
10024     /* ignore mouse cursor events */
10025     if (object_id == OBJID_CURSOR) return;
10026 
10027     if (!hwnd || is_our_logged_class(hwnd))
10028     {
10029         struct recvd_message msg;
10030 
10031         msg.hwnd = hwnd;
10032         msg.message = event;
10033         msg.flags = winevent_hook|wparam|lparam;
10034         msg.wParam = object_id;
10035         msg.lParam = child_id;
10036         msg.descr = "WEH";
10037         add_message(&msg);
10038     }
10039 }
10040 
10041 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
10042 static const WCHAR wszAnsi[] = {'U',0};
10043 
10044 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
10045 {
10046     switch (uMsg)
10047     {
10048     case CB_FINDSTRINGEXACT:
10049         trace("String: %p\n", (LPCWSTR)lParam);
10050         if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
10051             return 1;
10052         if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
10053             return 0;
10054         return -1;
10055     }
10056     return DefWindowProcW(hwnd, uMsg, wParam, lParam);
10057 }
10058 
10059 static const struct message WmGetTextLengthAfromW[] = {
10060     { WM_GETTEXTLENGTH, sent },
10061     { WM_GETTEXT, sent|optional },
10062     { 0 }
10063 };
10064 
10065 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
10066 
10067 /* dummy window proc for WM_GETTEXTLENGTH test */
10068 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
10069 {
10070     switch(msg)
10071     {
10072     case WM_GETTEXTLENGTH:
10073         return lstrlenW(dummy_window_text) + 37;  /* some random length */
10074     case WM_GETTEXT:
10075         lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
10076         return lstrlenW( (LPWSTR)lp );
10077     default:
10078         return DefWindowProcW( hwnd, msg, wp, lp );
10079     }
10080 }
10081 
10082 static void test_message_conversion(void)
10083 {
10084     static const WCHAR wszMsgConversionClass[] =
10085         {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
10086     WNDCLASSW cls;
10087     LRESULT lRes;
10088     HWND hwnd;
10089     WNDPROC wndproc, newproc;
10090     BOOL ret;
10091 
10092     cls.style = 0;
10093     cls.lpfnWndProc = MsgConversionProcW;
10094     cls.cbClsExtra = 0;
10095     cls.cbWndExtra = 0;
10096     cls.hInstance = GetModuleHandleW(NULL);
10097     cls.hIcon = NULL;
10098     cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
10099     cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
10100     cls.lpszMenuName = NULL;
10101     cls.lpszClassName = wszMsgConversionClass;
10102     /* this call will fail on Win9x, but that doesn't matter as this test is
10103      * meaningless on those platforms */
10104     if(!RegisterClassW(&cls)) return;
10105 
10106     hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
10107                            100, 100, 200, 200, 0, 0, 0, NULL);
10108     ok(hwnd != NULL, "Window creation failed\n");
10109 
10110     /* {W, A} -> A */
10111 
10112     wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
10113     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10114     ok(lRes == 0, "String should have been converted\n");
10115     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10116     ok(lRes == 1, "String shouldn't have been converted\n");
10117 
10118     /* {W, A} -> W */
10119 
10120     wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
10121     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10122     ok(lRes == 1, "String shouldn't have been converted\n");
10123     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10124     ok(lRes == 1, "String shouldn't have been converted\n");
10125 
10126     /* Synchronous messages */
10127 
10128     lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10129     ok(lRes == 0, "String should have been converted\n");
10130     lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10131     ok(lRes == 1, "String shouldn't have been converted\n");
10132 
10133     /* Asynchronous messages */
10134 
10135     SetLastError(0);
10136     lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10137     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10138         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10139     SetLastError(0);
10140     lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10141     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10142         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10143     SetLastError(0);
10144     lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10145     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10146         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10147     SetLastError(0);
10148     lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10149     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10150         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10151     SetLastError(0);
10152     lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10153     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10154         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10155     SetLastError(0);
10156     lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10157     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10158         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10159     SetLastError(0);
10160     lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
10161     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10162         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10163     SetLastError(0);
10164     lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
10165     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10166         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10167 
10168     /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
10169 
10170     hwnd = CreateWindowW (testWindowClassW, wszUnicode,
10171                           WS_OVERLAPPEDWINDOW,
10172                           100, 100, 200, 200, 0, 0, 0, NULL);
10173     assert(hwnd);
10174     flush_sequence();
10175     lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
10176     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
10177     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
10178         "got bad length %ld\n", lRes );
10179 
10180     flush_sequence();
10181     lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
10182                             hwnd, WM_GETTEXTLENGTH, 0, 0);
10183     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
10184     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
10185         "got bad length %ld\n", lRes );
10186 
10187     wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
10188     newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
10189     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
10190     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
10191                                      NULL, 0, NULL, NULL ) ||
10192         broken(lRes == lstrlenW(dummy_window_text) + 37),
10193         "got bad length %ld\n", lRes );
10194 
10195     SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc );  /* restore old wnd proc */
10196     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
10197     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
10198                                      NULL, 0, NULL, NULL ) ||
10199         broken(lRes == lstrlenW(dummy_window_text) + 37),
10200         "got bad length %ld\n", lRes );
10201 
10202     ret = DestroyWindow(hwnd);
10203     ok( ret, "DestroyWindow() error %d\n", GetLastError());
10204 }
10205 
10206 struct timer_info
10207 {
10208     HWND hWnd;
10209     HANDLE handles[2];
10210     DWORD id;
10211 };
10212 
10213 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
10214 {
10215 }
10216 
10217 #define TIMER_ID               0x19
10218 #define TIMER_COUNT_EXPECTED   100
10219 #define TIMER_COUNT_TOLERANCE  10
10220 
10221 static int count = 0;
10222 static void CALLBACK callback_count(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
10223 {
10224     count++;
10225 }
10226 
10227 static DWORD exception;
10228 static void CALLBACK callback_exception(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
10229 {
10230     count++;
10231     RaiseException(exception, 0, 0, NULL);
10232 }
10233 
10234 static DWORD WINAPI timer_thread_proc(LPVOID x)
10235 {
10236     struct timer_info *info = x;
10237     DWORD r;
10238 
10239     r = KillTimer(info->hWnd, 0x19);
10240     ok(r,"KillTimer failed in thread\n");
10241     r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
10242     ok(r,"SetTimer failed in thread\n");
10243     ok(r==TIMER_ID,"SetTimer id different\n");
10244     r = SetEvent(info->handles[0]);
10245     ok(r,"SetEvent failed in thread\n");
10246     return 0;
10247 }
10248 
10249 static void test_timers(void)
10250 {
10251     struct timer_info info;
10252     DWORD start;
10253     DWORD id;
10254     MSG msg;
10255 
10256     info.hWnd = CreateWindowA("TestWindowClass", NULL,
10257        WS_OVERLAPPEDWINDOW ,
10258        CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
10259        NULL, NULL, 0);
10260 
10261     info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
10262     ok(info.id, "SetTimer failed\n");
10263     ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
10264     info.handles[0] = CreateEventW(NULL,0,0,NULL);
10265     info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
10266 
10267     WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
10268 
10269     WaitForSingleObject(info.handles[1], INFINITE);
10270 
10271     CloseHandle(info.handles[0]);
10272     CloseHandle(info.handles[1]);
10273 
10274     ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
10275 
10276     /* Check the minimum allowed timeout for a timer.  MSDN indicates that it should be 10.0 ms,
10277      * which occurs sometimes, but most testing on the VMs indicates a minimum timeout closer to
10278      * 15.6 ms.  Since there is some measurement error between test runs we are allowing for
10279      * ±9 counts (~4 ms) around the expected value.
10280      */
10281     count = 0;
10282     id = SetTimer(info.hWnd, TIMER_ID, 0, callback_count);
10283     ok(id != 0, "did not get id from SetTimer.\n");
10284     ok(id==TIMER_ID, "SetTimer timer ID different\n");
10285     start = GetTickCount();
10286     while (GetTickCount()-start < 1001 && GetMessageA(&msg, info.hWnd, 0, 0))
10287         DispatchMessageA(&msg);
10288 ros_skip_flaky
10289 todo_wine
10290     ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE /* xp */
10291        || broken(abs(count-64) < TIMER_COUNT_TOLERANCE) /* most common */
10292        || broken(abs(count-43) < TIMER_COUNT_TOLERANCE) /* w2k3, win8 */,
10293        "did not get expected count for minimum timeout (%d != ~%d).\n",
10294        count, TIMER_COUNT_EXPECTED);
10295     ok(KillTimer(info.hWnd, id), "KillTimer failed\n");
10296     /* Perform the same check on SetSystemTimer (only available on w2k3 and older) */
10297     if (pSetSystemTimer)
10298     {
10299         int syscount = 0;
10300 
10301         count = 0;
10302         id = pSetSystemTimer(info.hWnd, TIMER_ID, 0, callback_count);
10303         ok(id != 0, "did not get id from SetSystemTimer.\n");
10304         ok(id==TIMER_ID, "SetTimer timer ID different\n");
10305         start = GetTickCount();
10306         while (GetTickCount()-start < 1001 && GetMessageA(&msg, info.hWnd, 0, 0))
10307         {
10308             if (msg.message == WM_SYSTIMER)
10309                 syscount++;
10310             DispatchMessageA(&msg);
10311         }
10312         ok(abs(syscount-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE
10313            || broken(abs(syscount-64) < TIMER_COUNT_TOLERANCE) /* most common */
10314            || broken(syscount > 4000 && syscount < 12000) /* win2k3sp0 */,
10315            "did not get expected count for minimum timeout (%d != ~%d).\n",
10316            syscount, TIMER_COUNT_EXPECTED);
10317         todo_wine ok(count == 0, "did not get expected count for callback timeout (%d != 0).\n",
10318                                  count);
10319         ok(pKillSystemTimer(info.hWnd, id), "KillSystemTimer failed\n");
10320     }
10321 
10322     ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
10323 }
10324 
10325 static void test_timers_no_wnd(void)
10326 {
10327     static UINT_PTR ids[0xffff];
10328     UINT_PTR id, id2;
10329     DWORD start;
10330     MSG msg;
10331     int i;
10332 
10333     count = 0;
10334     id = SetTimer(NULL, 0, 100, callback_count);
10335     ok(id != 0, "did not get id from SetTimer.\n");
10336     id2 = SetTimer(NULL, id, 200, callback_count);
10337     ok(id2 == id, "did not get same id from SetTimer when replacing (%li expected %li).\n", id2, id);
10338     Sleep(150);
10339     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
10340     ok(count == 0, "did not get zero count as expected (%i).\n", count);
10341     Sleep(150);
10342     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
10343     ok(count == 1, "did not get one count as expected (%i).\n", count);
10344     KillTimer(NULL, id);
10345     Sleep(250);
10346     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
10347     ok(count == 1, "killing replaced timer did not work (%i).\n", count);
10348 
10349     /* Check the minimum allowed timeout for a timer.  MSDN indicates that it should be 10.0 ms,
10350      * which occurs sometimes, but most testing on the VMs indicates a minimum timeout closer to
10351      * 15.6 ms.  Since there is some measurement error between test runs we are allowing for
10352      * ±9 counts (~4 ms) around the expected value.
10353      */
10354     count = 0;
10355     id = SetTimer(NULL, 0, 0, callback_count);
10356     ok(id != 0, "did not get id from SetTimer.\n");
10357     start = GetTickCount();
10358     while (GetTickCount()-start < 1001 && GetMessageA(&msg, NULL, 0, 0))
10359         DispatchMessageA(&msg);
10360 todo_wine
10361     ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE /* xp */
10362        || broken(abs(count-64) < TIMER_COUNT_TOLERANCE) /* most common */,
10363        "did not get expected count for minimum timeout (%d != ~%d).\n",
10364        count, TIMER_COUNT_EXPECTED);
10365     KillTimer(NULL, id);
10366     /* Note: SetSystemTimer doesn't support a NULL window, see test_timers */
10367 
10368     if (pSetCoalescableTimer)
10369     {
10370         count = 0;
10371         id = pSetCoalescableTimer(NULL, 0, 0, callback_count, 0);
10372         ok(id != 0, "SetCoalescableTimer failed with %u.\n", GetLastError());
10373         start = GetTickCount();
10374         while (GetTickCount()-start < 100 && GetMessageA(&msg, NULL, 0, 0))
10375             DispatchMessageA(&msg);
10376         ok(count > 1, "expected count > 1, got %d.\n", count);
10377         KillTimer(NULL, id);
10378     }
10379     else
10380         win_skip("SetCoalescableTimer not available.\n");
10381 
10382     /* Check what happens when we're running out of timers */
10383     for (i = 0; i < ARRAY_SIZE(ids); i++)
10384     {
10385         SetLastError(0xdeadbeef);
10386         ids[i] = SetTimer(NULL, 0, USER_TIMER_MAXIMUM, tfunc);
10387         if (!ids[i]) break;
10388     }
10389     ok(i != ARRAY_SIZE(ids), "all timers were created successfully\n");
10390     ok(GetLastError()==ERROR_NO_MORE_USER_HANDLES || broken(GetLastError()==0xdeadbeef),
10391             "GetLastError() = %d\n", GetLastError());
10392     while (i > 0) KillTimer(NULL, ids[--i]);
10393 }
10394 
10395 static void test_timers_exception(DWORD code)
10396 {
10397     UINT_PTR id;
10398     MSG msg;
10399 
10400     exception = code;
10401     id = SetTimer(NULL, 0, 1000, callback_exception);
10402     ok(id != 0, "did not get id from SetTimer.\n");
10403 
10404     memset(&msg, 0, sizeof(msg));
10405     msg.message = WM_TIMER;
10406     msg.wParam = id;
10407     msg.lParam = (LPARAM)callback_exception;
10408 
10409     count = 0;
10410     DispatchMessageA(&msg);
10411     ok(count == 1, "did not get one count as expected (%i).\n", count);
10412 
10413     KillTimer(NULL, id);
10414 }
10415 
10416 static void test_timers_exceptions(void)
10417 {
10418     test_timers_exception(EXCEPTION_ACCESS_VIOLATION);
10419     test_timers_exception(EXCEPTION_DATATYPE_MISALIGNMENT);
10420     test_timers_exception(EXCEPTION_BREAKPOINT);
10421     test_timers_exception(EXCEPTION_SINGLE_STEP);
10422     test_timers_exception(EXCEPTION_ARRAY_BOUNDS_EXCEEDED);
10423     test_timers_exception(EXCEPTION_FLT_DENORMAL_OPERAND);
10424     test_timers_exception(EXCEPTION_FLT_DIVIDE_BY_ZERO);
10425     test_timers_exception(EXCEPTION_FLT_INEXACT_RESULT);
10426     test_timers_exception(EXCEPTION_ILLEGAL_INSTRUCTION);
10427     test_timers_exception(0xE000BEEF); /* customer exception */
10428 }
10429 
10430 /* Various win events with arbitrary parameters */
10431 static const struct message WmWinEventsSeq[] = {
10432     { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
10433     { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
10434     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
10435     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
10436     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
10437     { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
10438     { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
10439     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
10440     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
10441     /* our win event hook ignores OBJID_CURSOR events */
10442     /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
10443     { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
10444     { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
10445     { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
10446     { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
10447     { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
10448     { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
10449     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
10450     { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
10451     { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
10452     { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
10453     { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
10454     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
10455     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
10456     { 0 }
10457 };
10458 static const struct message WmWinEventCaretSeq[] = {
10459     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
10460     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
10461     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
10462     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
10463     { 0 }
10464 };
10465 static const struct message WmWinEventCaretSeq_2[] = {
10466     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
10467     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
10468     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
10469     { 0 }
10470 };
10471 static const struct message WmWinEventAlertSeq[] = {
10472     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
10473     { 0 }
10474 };
10475 static const struct message WmWinEventAlertSeq_2[] = {
10476     /* create window in the thread proc */
10477     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
10478     /* our test event */
10479     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
10480     { 0 }
10481 };
10482 static const struct message WmGlobalHookSeq_1[] = {
10483     /* create window in the thread proc */
10484     { HCBT_CREATEWND, hook|lparam, 0, 2 },
10485     /* our test events */
10486     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
10487     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
10488     { 0 }
10489 };
10490 static const struct message WmGlobalHookSeq_2[] = {
10491     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
10492     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
10493     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
10494     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
10495     { 0 }
10496 };
10497 
10498 static const struct message WmMouseLLHookSeq[] = {
10499     { WM_MOUSEMOVE, hook },
10500     { WM_LBUTTONUP, hook },
10501     { WM_MOUSEMOVE, hook },
10502     { 0 }
10503 };
10504 
10505 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
10506 					 DWORD event,
10507 					 HWND hwnd,
10508 					 LONG object_id,
10509 					 LONG child_id,
10510 					 DWORD thread_id,
10511 					 DWORD event_time)
10512 {
10513     char buf[256];
10514 
10515     if (GetClassNameA(hwnd, buf, sizeof(buf)))
10516     {
10517 	if (!lstrcmpiA(buf, "TestWindowClass") ||
10518 	    !lstrcmpiA(buf, "static"))
10519 	{
10520 	    struct recvd_message msg;
10521 
10522             msg.hwnd = hwnd;
10523 	    msg.message = event;
10524 	    msg.flags = winevent_hook|wparam|lparam;
10525 	    msg.wParam = object_id;
10526 	    msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
10527             msg.descr = "WEH_2";
10528 	    add_message(&msg);
10529 	}
10530     }
10531 }
10532 
10533 static HHOOK hCBT_global_hook;
10534 static DWORD cbt_global_hook_thread_id;
10535 
10536 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
10537 {
10538     HWND hwnd;
10539     char buf[256];
10540 
10541     if (nCode == HCBT_SYSCOMMAND)
10542     {
10543 	struct recvd_message msg;
10544 
10545         msg.hwnd = 0;
10546 	msg.message = nCode;
10547 	msg.flags = hook|wparam|lparam;
10548 	msg.wParam = wParam;
10549 	msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
10550         msg.descr = "CBT_2";
10551 	add_message(&msg);
10552 
10553 	return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
10554     }
10555     /* WH_MOUSE_LL hook */
10556     if (nCode == HC_ACTION)
10557     {
10558         MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
10559 
10560         /* we can't test for real mouse events */
10561         if (mhll->flags & LLMHF_INJECTED)
10562         {
10563 	    struct recvd_message msg;
10564 
10565 	    memset (&msg, 0, sizeof (msg));
10566 	    msg.message = wParam;
10567 	    msg.flags = hook;
10568             msg.descr = "CBT_2";
10569 	    add_message(&msg);
10570         }
10571 	return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
10572     }
10573 
10574     /* Log also SetFocus(0) calls */
10575     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
10576 
10577     if (GetClassNameA(hwnd, buf, sizeof(buf)))
10578     {
10579 	if (!lstrcmpiA(buf, "TestWindowClass") ||
10580 	    !lstrcmpiA(buf, "static"))
10581 	{
10582 	    struct recvd_message msg;
10583 
10584             msg.hwnd = hwnd;
10585 	    msg.message = nCode;
10586 	    msg.flags = hook|wparam|lparam;
10587 	    msg.wParam = wParam;
10588 	    msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
10589             msg.descr = "CBT_2";
10590 	    add_message(&msg);
10591 	}
10592     }
10593     return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
10594 }
10595 
10596 static DWORD WINAPI win_event_global_thread_proc(void *param)
10597 {
10598     HWND hwnd;
10599     MSG msg;
10600     HANDLE hevent = *(HANDLE *)param;
10601 
10602     assert(pNotifyWinEvent);
10603 
10604     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
10605     assert(hwnd);
10606     trace("created thread window %p\n", hwnd);
10607 
10608     *(HWND *)param = hwnd;
10609 
10610     flush_sequence();
10611     /* this event should be received only by our new hook proc,
10612      * an old one does not expect an event from another thread.
10613      */
10614     pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
10615     SetEvent(hevent);
10616 
10617     while (GetMessageA(&msg, 0, 0, 0))
10618     {
10619 	TranslateMessage(&msg);
10620 	DispatchMessageA(&msg);
10621     }
10622     return 0;
10623 }
10624 
10625 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
10626 {
10627     HWND hwnd;
10628     MSG msg;
10629     HANDLE hevent = *(HANDLE *)param;
10630 
10631     flush_sequence();
10632     /* these events should be received only by our new hook proc,
10633      * an old one does not expect an event from another thread.
10634      */
10635 
10636     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
10637     assert(hwnd);
10638     trace("created thread window %p\n", hwnd);
10639 
10640     *(HWND *)param = hwnd;
10641 
10642     /* Windows doesn't like when a thread plays games with the focus,
10643        that leads to all kinds of misbehaviours and failures to activate
10644        a window. So, better keep next lines commented out.
10645     SetFocus(0);
10646     SetFocus(hwnd);*/
10647 
10648     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
10649     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
10650 
10651     SetEvent(hevent);
10652 
10653     while (GetMessageA(&msg, 0, 0, 0))
10654     {
10655 	TranslateMessage(&msg);
10656 	DispatchMessageA(&msg);
10657     }
10658     return 0;
10659 }
10660 
10661 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
10662 {
10663     HWND hwnd;
10664     MSG msg;
10665     HANDLE hevent = *(HANDLE *)param;
10666 
10667     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
10668     assert(hwnd);
10669     trace("created thread window %p\n", hwnd);
10670 
10671     *(HWND *)param = hwnd;
10672 
10673     flush_sequence();
10674 
10675     /* Windows doesn't like when a thread plays games with the focus,
10676      * that leads to all kinds of misbehaviours and failures to activate
10677      * a window. So, better don't generate a mouse click message below.
10678      */
10679     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10680     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
10681     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10682 
10683     SetEvent(hevent);
10684     while (GetMessageA(&msg, 0, 0, 0))
10685     {
10686         TranslateMessage(&msg);
10687         DispatchMessageA(&msg);
10688     }
10689     return 0;
10690 }
10691 
10692 static void test_winevents(void)
10693 {
10694     BOOL ret;
10695     MSG msg;
10696     HWND hwnd, hwnd2;
10697     UINT i;
10698     HANDLE hthread, hevent;
10699     DWORD tid;
10700     HWINEVENTHOOK hhook;
10701     const struct message *events = WmWinEventsSeq;
10702 
10703     hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
10704 			   WS_OVERLAPPEDWINDOW,
10705 			   CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
10706 			   NULL, NULL, 0);
10707     assert(hwnd);
10708 
10709     /****** start of global hook test *************/
10710     hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
10711     if (!hCBT_global_hook)
10712     {
10713         ok(DestroyWindow(hwnd), "failed to destroy window\n");
10714         skip( "cannot set global hook\n" );
10715         return;
10716     }
10717 
10718     hevent = CreateEventA(NULL, 0, 0, NULL);
10719     assert(hevent);
10720     hwnd2 = hevent;
10721 
10722     hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
10723     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
10724 
10725     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10726 
10727     ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
10728 
10729     flush_sequence();
10730     /* this one should be received only by old hook proc */
10731     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
10732     /* this one should be received only by old hook proc */
10733     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
10734 
10735     ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
10736 
10737     ret = UnhookWindowsHookEx(hCBT_global_hook);
10738     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
10739 
10740     PostThreadMessageA(tid, WM_QUIT, 0, 0);
10741     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10742     CloseHandle(hthread);
10743     CloseHandle(hevent);
10744     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10745     /****** end of global hook test *************/
10746 
10747     if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
10748     {
10749 	ok(DestroyWindow(hwnd), "failed to destroy window\n");
10750 	return;
10751     }
10752 
10753     flush_sequence();
10754 
10755     if (0)
10756     {
10757     /* this test doesn't pass under Win9x */
10758     /* win2k ignores events with hwnd == 0 */
10759     SetLastError(0xdeadbeef);
10760     pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
10761     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
10762        GetLastError() == 0xdeadbeef, /* Win9x */
10763        "unexpected error %d\n", GetLastError());
10764     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
10765     }
10766 
10767     for (i = 0; i < ARRAY_SIZE(WmWinEventsSeq); i++)
10768 	pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
10769 
10770     ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
10771 
10772     /****** start of event filtering test *************/
10773     hhook = pSetWinEventHook(
10774 	EVENT_OBJECT_SHOW, /* 0x8002 */
10775 	EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
10776 	GetModuleHandleA(0), win_event_global_hook_proc,
10777 	GetCurrentProcessId(), 0,
10778 	WINEVENT_INCONTEXT);
10779     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
10780 
10781     hevent = CreateEventA(NULL, 0, 0, NULL);
10782     assert(hevent);
10783     hwnd2 = hevent;
10784 
10785     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
10786     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
10787 
10788     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10789 
10790     ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
10791 
10792     flush_sequence();
10793     /* this one should be received only by old hook proc */
10794     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
10795     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
10796     /* this one should be received only by old hook proc */
10797     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
10798 
10799     ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
10800 
10801     ret = pUnhookWinEvent(hhook);
10802     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10803 
10804     PostThreadMessageA(tid, WM_QUIT, 0, 0);
10805     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10806     CloseHandle(hthread);
10807     CloseHandle(hevent);
10808     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10809     /****** end of event filtering test *************/
10810 
10811     /****** start of out of context event test *************/
10812     hhook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0,
10813         win_event_global_hook_proc, GetCurrentProcessId(), 0,
10814 	WINEVENT_OUTOFCONTEXT);
10815     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
10816 
10817     hevent = CreateEventA(NULL, 0, 0, NULL);
10818     assert(hevent);
10819     hwnd2 = hevent;
10820 
10821     flush_sequence();
10822 
10823     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
10824     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
10825 
10826     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10827 
10828     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
10829     /* process pending winevent messages */
10830     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
10831     ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
10832 
10833     flush_sequence();
10834     /* this one should be received only by old hook proc */
10835     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
10836     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
10837     /* this one should be received only by old hook proc */
10838     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
10839 
10840     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
10841     /* process pending winevent messages */
10842     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
10843     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
10844 
10845     ret = pUnhookWinEvent(hhook);
10846     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10847 
10848     PostThreadMessageA(tid, WM_QUIT, 0, 0);
10849     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10850     CloseHandle(hthread);
10851     CloseHandle(hevent);
10852     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10853     /****** end of out of context event test *************/
10854 
10855     /****** start of MOUSE_LL hook test *************/
10856     hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
10857     /* WH_MOUSE_LL is not supported on Win9x platforms */
10858     if (!hCBT_global_hook)
10859     {
10860         win_skip("Skipping WH_MOUSE_LL test on this platform\n");
10861         goto skip_mouse_ll_hook_test;
10862     }
10863 
10864     hevent = CreateEventA(NULL, 0, 0, NULL);
10865     assert(hevent);
10866     hwnd2 = hevent;
10867 
10868     hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
10869     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
10870 
10871     while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
10872         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
10873 
10874     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
10875     flush_sequence();
10876 
10877     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10878     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
10879     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10880 
10881     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
10882 
10883     ret = UnhookWindowsHookEx(hCBT_global_hook);
10884     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
10885 
10886     PostThreadMessageA(tid, WM_QUIT, 0, 0);
10887     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10888     CloseHandle(hthread);
10889     CloseHandle(hevent);
10890     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10891     /****** end of MOUSE_LL hook test *************/
10892 skip_mouse_ll_hook_test:
10893 
10894     ok(DestroyWindow(hwnd), "failed to destroy window\n");
10895 }
10896 
10897 static void test_set_hook(void)
10898 {
10899     BOOL ret;
10900     HHOOK hhook;
10901     HWINEVENTHOOK hwinevent_hook;
10902 
10903     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
10904     ok(hhook != 0, "local hook does not require hModule set to 0\n");
10905     UnhookWindowsHookEx(hhook);
10906 
10907     if (0)
10908     {
10909     /* this test doesn't pass under Win9x: BUG! */
10910     SetLastError(0xdeadbeef);
10911     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
10912     ok(!hhook, "global hook requires hModule != 0\n");
10913     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
10914     }
10915 
10916     SetLastError(0xdeadbeef);
10917     hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
10918     ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
10919     ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
10920        GetLastError() == 0xdeadbeef, /* Win9x */
10921        "unexpected error %d\n", GetLastError());
10922 
10923     SetLastError(0xdeadbeef);
10924     ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
10925     ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
10926        GetLastError() == 0xdeadbeef, /* Win9x */
10927        "unexpected error %d\n", GetLastError());
10928 
10929     if (!pSetWinEventHook || !pUnhookWinEvent) return;
10930 
10931     /* even process local incontext hooks require hmodule */
10932     SetLastError(0xdeadbeef);
10933     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10934         GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
10935     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
10936     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
10937        GetLastError() == 0xdeadbeef, /* Win9x */
10938        "unexpected error %d\n", GetLastError());
10939 
10940     /* even thread local incontext hooks require hmodule */
10941     SetLastError(0xdeadbeef);
10942     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10943         GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
10944     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
10945     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
10946        GetLastError() == 0xdeadbeef, /* Win9x */
10947        "unexpected error %d\n", GetLastError());
10948 
10949     if (0)
10950     {
10951     /* these 3 tests don't pass under Win9x */
10952     SetLastError(0xdeadbeef);
10953     hwinevent_hook = pSetWinEventHook(1, 0, 0, win_event_proc,
10954         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
10955     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
10956     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
10957 
10958     SetLastError(0xdeadbeef);
10959     hwinevent_hook = pSetWinEventHook(-1, 1, 0, win_event_proc,
10960         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
10961     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
10962     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
10963 
10964     SetLastError(0xdeadbeef);
10965     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10966         0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
10967     ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
10968     ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
10969     }
10970 
10971     SetLastError(0xdeadbeef);
10972     hwinevent_hook = pSetWinEventHook(0, 0, 0, win_event_proc,
10973         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
10974     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
10975     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
10976     ret = pUnhookWinEvent(hwinevent_hook);
10977     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10978 
10979 todo_wine {
10980     /* This call succeeds under win2k SP4, but fails under Wine.
10981        Does win2k test/use passed process id? */
10982     SetLastError(0xdeadbeef);
10983     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10984         0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
10985     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
10986     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
10987     ret = pUnhookWinEvent(hwinevent_hook);
10988     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10989 }
10990 
10991     SetLastError(0xdeadbeef);
10992     ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
10993     ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
10994 	GetLastError() == 0xdeadbeef, /* Win9x */
10995 	"unexpected error %d\n", GetLastError());
10996 }
10997 
10998 static HWND hook_hwnd;
10999 static HHOOK recursive_hook;
11000 static int hook_depth, max_hook_depth;
11001 
11002 static LRESULT WINAPI rec_get_message_hook(int code, WPARAM w, LPARAM l)
11003 {
11004     LRESULT res;
11005     MSG msg;
11006     BOOL b;
11007 
11008     hook_depth++;
11009     if(hook_depth > max_hook_depth)
11010         max_hook_depth = hook_depth;
11011 
11012     b = PeekMessageW(&msg, hook_hwnd, 0, 0, PM_NOREMOVE);
11013     ok(b, "PeekMessage failed\n");
11014 
11015     res = CallNextHookEx(recursive_hook, code, w, l);
11016 
11017     hook_depth--;
11018     return res;
11019 }
11020 
11021 static void test_recursive_hook(void)
11022 {
11023     MSG msg;
11024     BOOL b;
11025 
11026     hook_hwnd = CreateWindowA("Static", NULL, WS_POPUP, 0, 0, 200, 60, NULL, NULL, NULL, NULL);
11027     ok(hook_hwnd != NULL, "CreateWindow failed\n");
11028 
11029     recursive_hook = SetWindowsHookExW(WH_GETMESSAGE, rec_get_message_hook, NULL, GetCurrentThreadId());
11030     ok(recursive_hook != NULL, "SetWindowsHookEx failed\n");
11031 
11032     PostMessageW(hook_hwnd, WM_USER, 0, 0);
11033     PostMessageW(hook_hwnd, WM_USER+1, 0, 0);
11034 
11035     hook_depth = 0;
11036     GetMessageW(&msg, hook_hwnd, 0, 0);
11037     ok(15 <= max_hook_depth && max_hook_depth < 45, "max_hook_depth = %d\n", max_hook_depth);
11038     trace("max_hook_depth = %d\n", max_hook_depth);
11039 
11040     b = UnhookWindowsHookEx(recursive_hook);
11041     ok(b, "UnhokWindowsHookEx failed\n");
11042 
11043     DestroyWindow(hook_hwnd);
11044 }
11045 
11046 static const struct message ScrollWindowPaint1[] = {
11047     { WM_PAINT, sent },
11048     { WM_ERASEBKGND, sent|beginpaint },
11049     { WM_GETTEXTLENGTH, sent|optional },
11050     { WM_PAINT, sent|optional },
11051     { WM_NCPAINT, sent|beginpaint|optional },
11052     { WM_GETTEXT, sent|beginpaint|optional },
11053     { WM_GETTEXT, sent|beginpaint|optional },
11054     { WM_GETTEXT, sent|beginpaint|optional },
11055     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
11056     { WM_ERASEBKGND, sent|beginpaint|optional },
11057     { 0 }
11058 };
11059 
11060 static const struct message ScrollWindowPaint2[] = {
11061     { WM_PAINT, sent },
11062     { 0 }
11063 };
11064 
11065 static void test_scrollwindowex(void)
11066 {
11067     HWND hwnd, hchild;
11068     RECT rect={0,0,130,130};
11069 
11070     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
11071             WS_VISIBLE|WS_OVERLAPPEDWINDOW,
11072             100, 100, 200, 200, 0, 0, 0, NULL);
11073     ok (hwnd != 0, "Failed to create overlapped window\n");
11074     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
11075             WS_VISIBLE|WS_CAPTION|WS_CHILD,
11076             10, 10, 150, 150, hwnd, 0, 0, NULL);
11077     ok (hchild != 0, "Failed to create child\n");
11078     UpdateWindow(hwnd);
11079     flush_events();
11080     flush_sequence();
11081 
11082     /* scroll without the child window */
11083     trace("start scroll\n");
11084     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
11085             SW_ERASE|SW_INVALIDATE);
11086     ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE);
11087     trace("end scroll\n");
11088     flush_sequence();
11089     flush_events();
11090     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE);
11091     flush_events();
11092     flush_sequence();
11093 
11094     /* Now without the SW_ERASE flag */
11095     trace("start scroll\n");
11096     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
11097     ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE);
11098     trace("end scroll\n");
11099     flush_sequence();
11100     flush_events();
11101     ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", FALSE);
11102     flush_events();
11103     flush_sequence();
11104 
11105     /* now scroll the child window as well */
11106     trace("start scroll\n");
11107     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
11108             SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
11109     /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
11110     /* windows sometimes a WM_MOVE */
11111     ok_sequence(WmEmptySeq, "ScrollWindowEx", TRUE);
11112     trace("end scroll\n");
11113     flush_sequence();
11114     flush_events();
11115     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE);
11116     flush_events();
11117     flush_sequence();
11118 
11119     /* now scroll with ScrollWindow() */
11120     trace("start scroll with ScrollWindow\n");
11121     ScrollWindow( hwnd, 5, 5, NULL, NULL);
11122     trace("end scroll\n");
11123     flush_sequence();
11124     flush_events();
11125     ok_sequence(ScrollWindowPaint1, "ScrollWindow", FALSE);
11126 
11127     ok(DestroyWindow(hchild), "failed to destroy window\n");
11128     ok(DestroyWindow(hwnd), "failed to destroy window\n");
11129     flush_sequence();
11130 }
11131 
11132 static const struct message destroy_window_with_children[] = {
11133     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
11134     { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
11135     { 0x0090, sent|optional },
11136     { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
11137     { 0x0090, sent|optional },
11138     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
11139     { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
11140     { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
11141     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
11142     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
11143     { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
11144     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
11145     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
11146     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
11147     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
11148     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
11149     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
11150     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
11151     { 0 }
11152 };
11153 
11154 static void test_DestroyWindow(void)
11155 {
11156     BOOL ret;
11157     HWND parent, child1, child2, child3, child4, test;
11158     UINT_PTR child_id = WND_CHILD_ID + 1;
11159 
11160     parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
11161 			     100, 100, 200, 200, 0, 0, 0, NULL);
11162     assert(parent != 0);
11163     child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
11164 			     0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
11165     assert(child1 != 0);
11166     child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
11167 			     0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
11168     assert(child2 != 0);
11169     child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
11170 			     0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
11171     assert(child3 != 0);
11172     child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
11173 			     0, 0, 50, 50, parent, 0, 0, NULL);
11174     assert(child4 != 0);
11175 
11176     /* test owner/parent of child2 */
11177     test = GetParent(child2);
11178     ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
11179     ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
11180     if(pGetAncestor) {
11181         test = pGetAncestor(child2, GA_PARENT);
11182         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
11183     }
11184     test = GetWindow(child2, GW_OWNER);
11185     ok(!test, "wrong owner %p\n", test);
11186 
11187     test = SetParent(child2, parent);
11188     ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
11189 
11190     /* test owner/parent of the parent */
11191     test = GetParent(parent);
11192     ok(!test, "wrong parent %p\n", test);
11193     ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
11194     if(pGetAncestor) {
11195         test = pGetAncestor(parent, GA_PARENT);
11196         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
11197     }
11198     test = GetWindow(parent, GW_OWNER);
11199     ok(!test, "wrong owner %p\n", test);
11200 
11201     /* test owner/parent of child1 */
11202     test = GetParent(child1);
11203     ok(test == parent, "wrong parent %p\n", test);
11204     ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
11205     if(pGetAncestor) {
11206         test = pGetAncestor(child1, GA_PARENT);
11207         ok(test == parent, "wrong parent %p\n", test);
11208     }
11209     test = GetWindow(child1, GW_OWNER);
11210     ok(!test, "wrong owner %p\n", test);
11211 
11212     /* test owner/parent of child2 */
11213     test = GetParent(child2);
11214     ok(test == parent, "wrong parent %p\n", test);
11215     ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
11216     if(pGetAncestor) {
11217         test = pGetAncestor(child2, GA_PARENT);
11218         ok(test == parent, "wrong parent %p\n", test);
11219     }
11220     test = GetWindow(child2, GW_OWNER);
11221     ok(!test, "wrong owner %p\n", test);
11222 
11223     /* test owner/parent of child3 */
11224     test = GetParent(child3);
11225     ok(test == child1, "wrong parent %p\n", test);
11226     ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
11227     if(pGetAncestor) {
11228         test = pGetAncestor(child3, GA_PARENT);
11229         ok(test == child1, "wrong parent %p\n", test);
11230     }
11231     test = GetWindow(child3, GW_OWNER);
11232     ok(!test, "wrong owner %p\n", test);
11233 
11234     /* test owner/parent of child4 */
11235     test = GetParent(child4);
11236     ok(test == parent, "wrong parent %p\n", test);
11237     ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
11238     if(pGetAncestor) {
11239         test = pGetAncestor(child4, GA_PARENT);
11240         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
11241     }
11242     test = GetWindow(child4, GW_OWNER);
11243     ok(test == parent, "wrong owner %p\n", test);
11244 
11245     flush_sequence();
11246 
11247     trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
11248 	   parent, child1, child2, child3, child4);
11249 
11250     SetCapture(child4);
11251     test = GetCapture();
11252     ok(test == child4, "wrong capture window %p\n", test);
11253 
11254     test_DestroyWindow_flag = TRUE;
11255     ret = DestroyWindow(parent);
11256     ok( ret, "DestroyWindow() error %d\n", GetLastError());
11257     test_DestroyWindow_flag = FALSE;
11258     ok_sequence(destroy_window_with_children, "destroy window with children", FALSE);
11259 
11260     ok(!IsWindow(parent), "parent still exists\n");
11261     ok(!IsWindow(child1), "child1 still exists\n");
11262     ok(!IsWindow(child2), "child2 still exists\n");
11263     ok(!IsWindow(child3), "child3 still exists\n");
11264     ok(!IsWindow(child4), "child4 still exists\n");
11265 
11266     test = GetCapture();
11267     ok(!test, "wrong capture window %p\n", test);
11268 }
11269 
11270 
11271 static const struct message WmDispatchPaint[] = {
11272     { WM_NCPAINT, sent },
11273     { WM_GETTEXT, sent|defwinproc|optional },
11274     { WM_GETTEXT, sent|defwinproc|optional },
11275     { WM_ERASEBKGND, sent },
11276     { 0 }
11277 };
11278 
11279 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11280 {
11281     if (message == WM_PAINT) return 0;
11282     return MsgCheckProcA( hwnd, message, wParam, lParam );
11283 }
11284 
11285 static void test_DispatchMessage(void)
11286 {
11287     RECT rect;
11288     MSG msg;
11289     int count;
11290     HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
11291                                100, 100, 200, 200, 0, 0, 0, NULL);
11292     ShowWindow( hwnd, SW_SHOW );
11293     UpdateWindow( hwnd );
11294     flush_events();
11295     flush_sequence();
11296     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
11297 
11298     SetRect( &rect, -5, -5, 5, 5 );
11299     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
11300     count = 0;
11301     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
11302     {
11303         if (msg.message != WM_PAINT) DispatchMessageA( &msg );
11304         else
11305         {
11306             flush_sequence();
11307             DispatchMessageA( &msg );
11308             /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
11309             if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
11310             else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
11311             if (++count > 10) break;
11312         }
11313     }
11314     ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
11315 
11316     trace("now without DispatchMessage\n");
11317     flush_sequence();
11318     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
11319     count = 0;
11320     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
11321     {
11322         if (msg.message != WM_PAINT) DispatchMessageA( &msg );
11323         else
11324         {
11325             HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
11326             flush_sequence();
11327             /* this will send WM_NCCPAINT just like DispatchMessage does */
11328             GetUpdateRgn( hwnd, hrgn, TRUE );
11329             ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
11330             DeleteObject( hrgn );
11331             GetClientRect( hwnd, &rect );
11332             ValidateRect( hwnd, &rect );  /* this will stop WM_PAINTs */
11333             ok( !count, "Got multiple WM_PAINTs\n" );
11334             if (++count > 10) break;
11335         }
11336     }
11337 
11338     flush_sequence();
11339     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
11340     count = 0;
11341     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
11342     {
11343         if (msg.message != WM_PAINT) DispatchMessageA( &msg );
11344         else
11345         {
11346             HDC hdc;
11347 
11348             flush_sequence();
11349             hdc = BeginPaint( hwnd, NULL );
11350             ok( !hdc, "got valid hdc %p from BeginPaint\n", hdc );
11351             ok( !EndPaint( hwnd, NULL ), "EndPaint succeeded\n" );
11352             ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
11353             ok( !count, "Got multiple WM_PAINTs\n" );
11354             if (++count > 10) break;
11355         }
11356     }
11357     DestroyWindow(hwnd);
11358 }
11359 
11360 
11361 static const struct message WmUser[] = {
11362     { WM_USER, sent },
11363     { 0 }
11364 };
11365 
11366 struct sendmsg_info
11367 {
11368     HWND  hwnd;
11369     DWORD timeout;
11370     DWORD ret;
11371 };
11372 
11373 static DWORD CALLBACK send_msg_thread( LPVOID arg )
11374 {
11375     struct sendmsg_info *info = arg;
11376     SetLastError( 0xdeadbeef );
11377     info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
11378     if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT ||
11379                         broken(GetLastError() == 0),  /* win9x */
11380                         "unexpected error %d\n", GetLastError());
11381     return 0;
11382 }
11383 
11384 static void wait_for_thread( HANDLE thread )
11385 {
11386     while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
11387     {
11388         MSG msg;
11389         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA(&msg);
11390     }
11391 }
11392 
11393 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11394 {
11395     if (message == WM_USER) Sleep(200);
11396     return MsgCheckProcA( hwnd, message, wParam, lParam );
11397 }
11398 
11399 static void test_SendMessageTimeout(void)
11400 {
11401     HANDLE thread;
11402     struct sendmsg_info info;
11403     DWORD tid;
11404     BOOL is_win9x;
11405 
11406     info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
11407                                100, 100, 200, 200, 0, 0, 0, NULL);
11408     flush_events();
11409     flush_sequence();
11410 
11411     info.timeout = 1000;
11412     info.ret = 0xdeadbeef;
11413     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11414     wait_for_thread( thread );
11415     CloseHandle( thread );
11416     ok( info.ret == 1, "SendMessageTimeout failed\n" );
11417     ok_sequence( WmUser, "WmUser", FALSE );
11418 
11419     info.timeout = 1;
11420     info.ret = 0xdeadbeef;
11421     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11422     Sleep(100);  /* SendMessageTimeout should time out here */
11423     wait_for_thread( thread );
11424     CloseHandle( thread );
11425     ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
11426     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
11427 
11428     /* 0 means infinite timeout (but not on win9x) */
11429     info.timeout = 0;
11430     info.ret = 0xdeadbeef;
11431     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11432     Sleep(100);
11433     wait_for_thread( thread );
11434     CloseHandle( thread );
11435     is_win9x = !info.ret;
11436     if (is_win9x) ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
11437     else ok_sequence( WmUser, "WmUser", FALSE );
11438 
11439     /* timeout is treated as signed despite the prototype (but not on win9x) */
11440     info.timeout = 0x7fffffff;
11441     info.ret = 0xdeadbeef;
11442     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11443     Sleep(100);
11444     wait_for_thread( thread );
11445     CloseHandle( thread );
11446     ok( info.ret == 1, "SendMessageTimeout failed\n" );
11447     ok_sequence( WmUser, "WmUser", FALSE );
11448 
11449     info.timeout = 0x80000000;
11450     info.ret = 0xdeadbeef;
11451     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11452     Sleep(100);
11453     wait_for_thread( thread );
11454     CloseHandle( thread );
11455     if (is_win9x)
11456     {
11457         ok( info.ret == 1, "SendMessageTimeout failed\n" );
11458         ok_sequence( WmUser, "WmUser", FALSE );
11459     }
11460     else
11461     {
11462         ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
11463         ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
11464     }
11465 
11466     /* now check for timeout during message processing */
11467     SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
11468     info.timeout = 100;
11469     info.ret = 0xdeadbeef;
11470     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11471     wait_for_thread( thread );
11472     CloseHandle( thread );
11473     /* we should time out but still get the message */
11474     ok( info.ret == 0, "SendMessageTimeout failed\n" );
11475     ok_sequence( WmUser, "WmUser", FALSE );
11476 
11477     DestroyWindow( info.hwnd );
11478 }
11479 
11480 
11481 /****************** edit message test *************************/
11482 #define ID_EDIT 0x1234
11483 static const struct message sl_edit_setfocus[] =
11484 {
11485     { HCBT_SETFOCUS, hook },
11486     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11487     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11488     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11489     { WM_SETFOCUS, sent|wparam, 0 },
11490     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11491     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 },
11492     { WM_CTLCOLOREDIT, sent|parent },
11493     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11494     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11495     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11496     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11497     { 0 }
11498 };
11499 static const struct message sl_edit_invisible[] =
11500 {
11501     { HCBT_SETFOCUS, hook },
11502     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11503     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11504     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11505     { WM_KILLFOCUS, sent|parent },
11506     { WM_SETFOCUS, sent },
11507     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11508     { 0 }
11509 };
11510 static const struct message ml_edit_setfocus[] =
11511 {
11512     { HCBT_SETFOCUS, hook },
11513     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11514     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11515     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11516     { WM_SETFOCUS, sent|wparam, 0 },
11517     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11518     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11519     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11520     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11521     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11522     { 0 }
11523 };
11524 static const struct message sl_edit_killfocus[] =
11525 {
11526     { HCBT_SETFOCUS, hook },
11527     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11528     { WM_KILLFOCUS, sent|wparam, 0 },
11529     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11530     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11531     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
11532     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
11533     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
11534     { 0 }
11535 };
11536 static const struct message sl_edit_lbutton_dblclk[] =
11537 {
11538     { WM_LBUTTONDBLCLK, sent },
11539     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11540     { 0 }
11541 };
11542 static const struct message sl_edit_lbutton_down[] =
11543 {
11544     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
11545     { HCBT_SETFOCUS, hook },
11546     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11547     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11548     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11549     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
11550     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11551     { WM_CTLCOLOREDIT, sent|parent },
11552     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11553     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11554     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11555     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11556     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11557     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11558     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11559     { WM_CTLCOLOREDIT, sent|parent|optional },
11560     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11561     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11562     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11563     { 0 }
11564 };
11565 static const struct message ml_edit_lbutton_down[] =
11566 {
11567     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
11568     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11569     { HCBT_SETFOCUS, hook },
11570     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11571     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11572     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11573     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
11574     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11575     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11576     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11577     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11578     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11579     { 0 }
11580 };
11581 static const struct message sl_edit_lbutton_up[] =
11582 {
11583     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
11584     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11585     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
11586     { WM_CAPTURECHANGED, sent|defwinproc },
11587     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11588     { 0 }
11589 };
11590 static const struct message ml_edit_lbutton_up[] =
11591 {
11592     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
11593     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
11594     { WM_CAPTURECHANGED, sent|defwinproc },
11595     { 0 }
11596 };
11597 
11598 static WNDPROC old_edit_proc;
11599 
11600 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11601 {
11602     static LONG defwndproc_counter = 0;
11603     LRESULT ret;
11604     struct recvd_message msg;
11605 
11606     if (ignore_message( message )) return 0;
11607 
11608     msg.hwnd = hwnd;
11609     msg.message = message;
11610     msg.flags = sent|wparam|lparam;
11611     if (defwndproc_counter) msg.flags |= defwinproc;
11612     msg.wParam = wParam;
11613     msg.lParam = lParam;
11614     msg.descr = "edit";
11615     add_message(&msg);
11616 
11617     defwndproc_counter++;
11618     ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
11619     defwndproc_counter--;
11620 
11621     return ret;
11622 }
11623 
11624 static void subclass_edit(void)
11625 {
11626     WNDCLASSA cls;
11627 
11628     if (!GetClassInfoA(0, "edit", &cls)) assert(0);
11629 
11630     old_edit_proc = cls.lpfnWndProc;
11631 
11632     cls.hInstance = GetModuleHandleA(NULL);
11633     cls.lpfnWndProc = edit_hook_proc;
11634     cls.lpszClassName = "my_edit_class";
11635     UnregisterClassA(cls.lpszClassName, cls.hInstance);
11636     if (!RegisterClassA(&cls)) assert(0);
11637 }
11638 
11639 static void test_edit_messages(void)
11640 {
11641     HWND hwnd, parent;
11642     DWORD dlg_code;
11643 
11644     subclass_edit();
11645     log_all_parent_messages++;
11646 
11647     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11648                              100, 100, 200, 200, 0, 0, 0, NULL);
11649     ok (parent != 0, "Failed to create parent window\n");
11650 
11651     /* test single line edit */
11652     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
11653 			   0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
11654     ok(hwnd != 0, "Failed to create edit window\n");
11655 
11656     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
11657     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
11658 
11659     flush_sequence();
11660     SetFocus(hwnd);
11661     ok_sequence(sl_edit_invisible, "SetFocus(hwnd) on an invisible edit", FALSE);
11662 
11663     ShowWindow(hwnd, SW_SHOW);
11664     UpdateWindow(hwnd);
11665     SetFocus(0);
11666     flush_sequence();
11667 
11668     SetFocus(hwnd);
11669     ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
11670 
11671     SetFocus(0);
11672     ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
11673 
11674     SetFocus(0);
11675     ReleaseCapture();
11676     flush_sequence();
11677 
11678     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
11679     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
11680 
11681     SetFocus(0);
11682     ReleaseCapture();
11683     flush_sequence();
11684 
11685     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
11686     ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
11687 
11688     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
11689     ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
11690 
11691     DestroyWindow(hwnd);
11692 
11693     /* test multiline edit */
11694     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
11695 			   0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
11696     ok(hwnd != 0, "Failed to create edit window\n");
11697 
11698     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
11699     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
11700        "wrong dlg_code %08x\n", dlg_code);
11701 
11702     ShowWindow(hwnd, SW_SHOW);
11703     UpdateWindow(hwnd);
11704     SetFocus(0);
11705     flush_sequence();
11706 
11707     SetFocus(hwnd);
11708     ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
11709 
11710     SetFocus(0);
11711     ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
11712 
11713     SetFocus(0);
11714     ReleaseCapture();
11715     flush_sequence();
11716 
11717     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
11718     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
11719 
11720     SetFocus(0);
11721     ReleaseCapture();
11722     flush_sequence();
11723 
11724     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
11725     ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
11726 
11727     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
11728     ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
11729 
11730     DestroyWindow(hwnd);
11731     DestroyWindow(parent);
11732 
11733     log_all_parent_messages--;
11734 }
11735 
11736 /**************************** End of Edit test ******************************/
11737 
11738 static const struct message WmKeyDownSkippedSeq[] =
11739 {
11740     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
11741     { 0 }
11742 };
11743 static const struct message WmKeyDownWasDownSkippedSeq[] =
11744 {
11745     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x40000001 }, /* XP */
11746     { 0 }
11747 };
11748 static const struct message WmKeyUpSkippedSeq[] =
11749 {
11750     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
11751     { 0 }
11752 };
11753 static const struct message WmUserKeyUpSkippedSeq[] =
11754 {
11755     { WM_USER, sent },
11756     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
11757     { 0 }
11758 };
11759 
11760 #define EV_STOP 0
11761 #define EV_SENDMSG 1
11762 #define EV_ACK 2
11763 
11764 struct peekmsg_info
11765 {
11766     HWND  hwnd;
11767     HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
11768 };
11769 
11770 static DWORD CALLBACK send_msg_thread_2(void *param)
11771 {
11772     DWORD ret;
11773     struct peekmsg_info *info = param;
11774 
11775     trace("thread: looping\n");
11776     SetEvent(info->hevent[EV_ACK]);
11777 
11778     while (1)
11779     {
11780         ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
11781 
11782         switch (ret)
11783         {
11784         case WAIT_OBJECT_0 + EV_STOP:
11785             trace("thread: exiting\n");
11786             return 0;
11787 
11788         case WAIT_OBJECT_0 + EV_SENDMSG:
11789             trace("thread: sending message\n");
11790             ret = SendNotifyMessageA(info->hwnd, WM_USER, 0, 0);
11791             ok(ret, "SendNotifyMessageA failed error %u\n", GetLastError());
11792             SetEvent(info->hevent[EV_ACK]);
11793             break;
11794 
11795         default:
11796             trace("unexpected return: %04x\n", ret);
11797             assert(0);
11798             break;
11799         }
11800     }
11801     return 0;
11802 }
11803 
11804 static void test_PeekMessage(void)
11805 {
11806     MSG msg;
11807     HANDLE hthread;
11808     DWORD tid, qstatus;
11809     UINT qs_all_input = QS_ALLINPUT;
11810     UINT qs_input = QS_INPUT;
11811     BOOL ret;
11812     struct peekmsg_info info;
11813 
11814     info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
11815                               100, 100, 200, 200, 0, 0, 0, NULL);
11816     assert(info.hwnd);
11817     ShowWindow(info.hwnd, SW_SHOW);
11818     UpdateWindow(info.hwnd);
11819     SetFocus(info.hwnd);
11820 
11821     info.hevent[EV_STOP] = CreateEventA(NULL, 0, 0, NULL);
11822     info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
11823     info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
11824 
11825     hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
11826     WaitForSingleObject(info.hevent[EV_ACK], 10000);
11827 
11828     flush_events();
11829     flush_sequence();
11830 
11831     SetLastError(0xdeadbeef);
11832     qstatus = GetQueueStatus(qs_all_input);
11833     if (GetLastError() == ERROR_INVALID_FLAGS)
11834     {
11835         trace("QS_RAWINPUT not supported on this platform\n");
11836         qs_all_input &= ~QS_RAWINPUT;
11837         qs_input &= ~QS_RAWINPUT;
11838     }
11839     if (qstatus & QS_POSTMESSAGE)
11840     {
11841         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) /* nothing */ ;
11842         qstatus = GetQueueStatus(qs_all_input);
11843     }
11844     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
11845 
11846     trace("signalling to send message\n");
11847     SetEvent(info.hevent[EV_SENDMSG]);
11848     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11849 
11850     /* pass invalid QS_xxxx flags */
11851     SetLastError(0xdeadbeef);
11852     qstatus = GetQueueStatus(0xffffffff);
11853     ok(qstatus == 0 || broken(qstatus)  /* win9x */, "GetQueueStatus should fail: %08x\n", qstatus);
11854     if (!qstatus)
11855     {
11856         ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
11857         qstatus = GetQueueStatus(qs_all_input);
11858     }
11859     qstatus &= ~MAKELONG( 0x4000, 0x4000 );  /* sometimes set on Win95 */
11860     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
11861        "wrong qstatus %08x\n", qstatus);
11862 
11863     msg.message = 0;
11864     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11865     ok(!ret,
11866        "PeekMessageA should have returned FALSE instead of msg %04x\n",
11867         msg.message);
11868     ok_sequence(WmUser, "WmUser", FALSE);
11869 
11870     qstatus = GetQueueStatus(qs_all_input);
11871     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
11872 
11873     keybd_event('N', 0, 0, 0);
11874     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
11875     qstatus = GetQueueStatus(qs_all_input);
11876     if (!(qstatus & MAKELONG(QS_KEY, QS_KEY)))
11877     {
11878         skip( "queuing key events not supported\n" );
11879         goto done;
11880     }
11881     ok(qstatus == MAKELONG(QS_KEY, QS_KEY) ||
11882        /* keybd_event seems to trigger a sent message on NT4 */
11883        qstatus == MAKELONG(QS_KEY|QS_SENDMESSAGE, QS_KEY|QS_SENDMESSAGE),
11884        "wrong qstatus %08x\n", qstatus);
11885 
11886     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11887     qstatus = GetQueueStatus(qs_all_input);
11888     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY) ||
11889        qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
11890        "wrong qstatus %08x\n", qstatus);
11891 
11892     InvalidateRect(info.hwnd, NULL, FALSE);
11893     qstatus = GetQueueStatus(qs_all_input);
11894     ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY) ||
11895        qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
11896        "wrong qstatus %08x\n", qstatus);
11897 
11898     trace("signalling to send message\n");
11899     SetEvent(info.hevent[EV_SENDMSG]);
11900     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11901 
11902     qstatus = GetQueueStatus(qs_all_input);
11903     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11904        "wrong qstatus %08x\n", qstatus);
11905 
11906     msg.message = 0;
11907     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
11908     if (ret && msg.message == WM_CHAR)
11909     {
11910         win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
11911         goto done;
11912     }
11913     ok(!ret,
11914        "PeekMessageA should have returned FALSE instead of msg %04x\n",
11915         msg.message);
11916     if (!sequence_cnt)  /* nt4 doesn't fetch anything with PM_QS_* flags */
11917     {
11918         win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
11919         goto done;
11920     }
11921     ok_sequence(WmUser, "WmUser", FALSE);
11922 
11923     qstatus = GetQueueStatus(qs_all_input);
11924     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11925        "wrong qstatus %08x\n", qstatus);
11926 
11927     trace("signalling to send message\n");
11928     SetEvent(info.hevent[EV_SENDMSG]);
11929     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11930 
11931     qstatus = GetQueueStatus(qs_all_input);
11932     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11933        "wrong qstatus %08x\n", qstatus);
11934 
11935     msg.message = 0;
11936     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE );
11937     ok(!ret,
11938        "PeekMessageA should have returned FALSE instead of msg %04x\n",
11939         msg.message);
11940     ok_sequence(WmUser, "WmUser", FALSE);
11941 
11942     qstatus = GetQueueStatus(qs_all_input);
11943     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11944        "wrong qstatus %08x\n", qstatus);
11945 
11946     msg.message = 0;
11947     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
11948     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11949        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11950        ret, msg.message, msg.wParam);
11951     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11952 
11953     qstatus = GetQueueStatus(qs_all_input);
11954     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
11955        "wrong qstatus %08x\n", qstatus);
11956 
11957     msg.message = 0;
11958     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
11959     ok(!ret,
11960        "PeekMessageA should have returned FALSE instead of msg %04x\n",
11961         msg.message);
11962     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11963 
11964     qstatus = GetQueueStatus(qs_all_input);
11965     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
11966        "wrong qstatus %08x\n", qstatus);
11967 
11968     msg.message = 0;
11969     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
11970     ok(ret && msg.message == WM_PAINT,
11971        "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
11972     DispatchMessageA(&msg);
11973     ok_sequence(WmPaint, "WmPaint", FALSE);
11974 
11975     qstatus = GetQueueStatus(qs_all_input);
11976     ok(qstatus == MAKELONG(0, QS_KEY),
11977        "wrong qstatus %08x\n", qstatus);
11978 
11979     msg.message = 0;
11980     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
11981     ok(!ret,
11982        "PeekMessageA should have returned FALSE instead of msg %04x\n",
11983         msg.message);
11984     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11985 
11986     qstatus = GetQueueStatus(qs_all_input);
11987     ok(qstatus == MAKELONG(0, QS_KEY),
11988        "wrong qstatus %08x\n", qstatus);
11989 
11990     trace("signalling to send message\n");
11991     SetEvent(info.hevent[EV_SENDMSG]);
11992     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11993 
11994     qstatus = GetQueueStatus(qs_all_input);
11995     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
11996        "wrong qstatus %08x\n", qstatus);
11997 
11998     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11999 
12000     qstatus = GetQueueStatus(qs_all_input);
12001     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
12002        "wrong qstatus %08x\n", qstatus);
12003 
12004     msg.message = 0;
12005     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
12006     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
12007        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
12008        ret, msg.message, msg.wParam);
12009     ok_sequence(WmUser, "WmUser", FALSE);
12010 
12011     qstatus = GetQueueStatus(qs_all_input);
12012     ok(qstatus == MAKELONG(0, QS_KEY),
12013        "wrong qstatus %08x\n", qstatus);
12014 
12015     msg.message = 0;
12016     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
12017     ok(!ret,
12018        "PeekMessageA should have returned FALSE instead of msg %04x\n",
12019         msg.message);
12020     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12021 
12022     qstatus = GetQueueStatus(qs_all_input);
12023     ok(qstatus == MAKELONG(0, QS_KEY),
12024        "wrong qstatus %08x\n", qstatus);
12025 
12026     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
12027 
12028     qstatus = GetQueueStatus(qs_all_input);
12029     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
12030        "wrong qstatus %08x\n", qstatus);
12031 
12032     trace("signalling to send message\n");
12033     SetEvent(info.hevent[EV_SENDMSG]);
12034     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
12035 
12036     qstatus = GetQueueStatus(qs_all_input);
12037     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
12038        "wrong qstatus %08x\n", qstatus);
12039 
12040     msg.message = 0;
12041     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
12042     ok(!ret,
12043        "PeekMessageA should have returned FALSE instead of msg %04x\n",
12044         msg.message);
12045     ok_sequence(WmUser, "WmUser", FALSE);
12046 
12047     qstatus = GetQueueStatus(qs_all_input);
12048     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
12049        "wrong qstatus %08x\n", qstatus);
12050 
12051     msg.message = 0;
12052     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
12053         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
12054     else /* workaround for a missing QS_RAWINPUT support */
12055         ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
12056     ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
12057        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
12058        ret, msg.message, msg.wParam);
12059     ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
12060 
12061     qstatus = GetQueueStatus(qs_all_input);
12062     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
12063        "wrong qstatus %08x\n", qstatus);
12064 
12065     msg.message = 0;
12066     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
12067         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
12068     else /* workaround for a missing QS_RAWINPUT support */
12069         ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
12070     ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
12071        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYUP wParam 'N'\n",
12072        ret, msg.message, msg.wParam);
12073     ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
12074 
12075     qstatus = GetQueueStatus(qs_all_input);
12076     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
12077        "wrong qstatus %08x\n", qstatus);
12078 
12079     msg.message = 0;
12080     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
12081     ok(!ret,
12082        "PeekMessageA should have returned FALSE instead of msg %04x\n",
12083         msg.message);
12084     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12085 
12086     qstatus = GetQueueStatus(qs_all_input);
12087     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
12088        "wrong qstatus %08x\n", qstatus);
12089 
12090     msg.message = 0;
12091     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
12092     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
12093        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
12094        ret, msg.message, msg.wParam);
12095     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12096 
12097     qstatus = GetQueueStatus(qs_all_input);
12098     ok(qstatus == 0,
12099        "wrong qstatus %08x\n", qstatus);
12100 
12101     msg.message = 0;
12102     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
12103     ok(!ret,
12104        "PeekMessageA should have returned FALSE instead of msg %04x\n",
12105         msg.message);
12106     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12107 
12108     qstatus = GetQueueStatus(qs_all_input);
12109     ok(qstatus == 0,
12110        "wrong qstatus %08x\n", qstatus);
12111 
12112     /* test whether presence of the quit flag in the queue affects
12113      * the queue state
12114      */
12115     PostQuitMessage(0x1234abcd);
12116 
12117     qstatus = GetQueueStatus(qs_all_input);
12118     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
12119        "wrong qstatus %08x\n", qstatus);
12120 
12121     PostMessageA(info.hwnd, WM_USER, 0, 0);
12122 
12123     qstatus = GetQueueStatus(qs_all_input);
12124     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
12125        "wrong qstatus %08x\n", qstatus);
12126 
12127     msg.message = 0;
12128     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
12129     ok(ret && msg.message == WM_USER,
12130        "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
12131     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12132 
12133     qstatus = GetQueueStatus(qs_all_input);
12134     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
12135        "wrong qstatus %08x\n", qstatus);
12136 
12137     msg.message = 0;
12138     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
12139     ok(ret && msg.message == WM_QUIT,
12140        "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
12141     ok(msg.wParam == 0x1234abcd, "got wParam %08lx instead of 0x1234abcd\n", msg.wParam);
12142     ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
12143     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12144 
12145     qstatus = GetQueueStatus(qs_all_input);
12146 todo_wine {
12147     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
12148        "wrong qstatus %08x\n", qstatus);
12149 }
12150 
12151     msg.message = 0;
12152     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
12153     ok(!ret,
12154        "PeekMessageA should have returned FALSE instead of msg %04x\n",
12155         msg.message);
12156     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12157 
12158     qstatus = GetQueueStatus(qs_all_input);
12159     ok(qstatus == 0,
12160        "wrong qstatus %08x\n", qstatus);
12161 
12162     /* some GetMessage tests */
12163 
12164     keybd_event('N', 0, 0, 0);
12165     qstatus = GetQueueStatus(qs_all_input);
12166     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
12167 
12168     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
12169     qstatus = GetQueueStatus(qs_all_input);
12170     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
12171 
12172     if (qstatus)
12173     {
12174         ret = GetMessageA( &msg, 0, 0, 0 );
12175         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
12176            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
12177            ret, msg.message, msg.wParam);
12178         qstatus = GetQueueStatus(qs_all_input);
12179         ok(qstatus == MAKELONG(0, QS_KEY), "wrong qstatus %08x\n", qstatus);
12180     }
12181 
12182     if (qstatus)
12183     {
12184         ret = GetMessageA( &msg, 0, 0, 0 );
12185         ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
12186            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
12187            ret, msg.message, msg.wParam);
12188         ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
12189         qstatus = GetQueueStatus(qs_all_input);
12190         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
12191     }
12192 
12193     keybd_event('N', 0, 0, 0);
12194     qstatus = GetQueueStatus(qs_all_input);
12195     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
12196 
12197     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
12198     qstatus = GetQueueStatus(qs_all_input);
12199     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
12200 
12201     if (qstatus & (QS_KEY << 16))
12202     {
12203         ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
12204         ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
12205            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
12206            ret, msg.message, msg.wParam);
12207         ok_sequence(WmKeyDownWasDownSkippedSeq, "WmKeyDownWasDownSkippedSeq", FALSE);
12208         qstatus = GetQueueStatus(qs_all_input);
12209         ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
12210     }
12211 
12212     if (qstatus)
12213     {
12214         ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
12215         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
12216            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
12217            ret, msg.message, msg.wParam);
12218         qstatus = GetQueueStatus(qs_all_input);
12219         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
12220     }
12221 
12222     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
12223     qstatus = GetQueueStatus(qs_all_input);
12224     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
12225 
12226     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
12227     qstatus = GetQueueStatus(qs_all_input);
12228     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
12229 
12230     trace("signalling to send message\n");
12231     SetEvent(info.hevent[EV_SENDMSG]);
12232     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
12233     qstatus = GetQueueStatus(qs_all_input);
12234     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
12235        "wrong qstatus %08x\n", qstatus);
12236 
12237     if (qstatus & (QS_KEY << 16))
12238     {
12239         ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
12240         ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
12241            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
12242            ret, msg.message, msg.wParam);
12243         ok_sequence(WmUserKeyUpSkippedSeq, "WmUserKeyUpSkippedSeq", FALSE);
12244         qstatus = GetQueueStatus(qs_all_input);
12245         ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
12246     }
12247 
12248     if (qstatus)
12249     {
12250         ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
12251         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
12252            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
12253            ret, msg.message, msg.wParam);
12254         qstatus = GetQueueStatus(qs_all_input);
12255         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
12256     }
12257 
12258     PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
12259     ret = PeekMessageA(&msg, (HWND)-1, 0, 0, PM_NOREMOVE);
12260     ok(ret == TRUE, "wrong ret %d\n", ret);
12261     ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
12262     ret = GetMessageA(&msg, (HWND)-1, 0, 0);
12263     ok(ret == TRUE, "wrong ret %d\n", ret);
12264     ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
12265 
12266     PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
12267     ret = PeekMessageA(&msg, (HWND)1, 0, 0, PM_NOREMOVE);
12268     ok(ret == TRUE, "wrong ret %d\n", ret);
12269     ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
12270     ret = GetMessageA(&msg, (HWND)1, 0, 0);
12271     ok(ret == TRUE, "wrong ret %d\n", ret);
12272     ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
12273 
12274     PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
12275     ret = PeekMessageA(&msg, (HWND)0xffff, 0, 0, PM_NOREMOVE);
12276     ok(ret == TRUE, "wrong ret %d\n", ret);
12277     ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
12278     ret = GetMessageA(&msg, (HWND)0xffff, 0, 0);
12279     ok(ret == TRUE, "wrong ret %d\n", ret);
12280     ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
12281 
12282 done:
12283     trace("signalling to exit\n");
12284     SetEvent(info.hevent[EV_STOP]);
12285 
12286     WaitForSingleObject(hthread, INFINITE);
12287 
12288     CloseHandle(hthread);
12289     CloseHandle(info.hevent[0]);
12290     CloseHandle(info.hevent[1]);
12291     CloseHandle(info.hevent[2]);
12292 
12293     DestroyWindow(info.hwnd);
12294 }
12295 
12296 static void wait_move_event(HWND hwnd, int x, int y)
12297 {
12298     MSG msg;
12299     DWORD time;
12300     BOOL ret;
12301 
12302     time = GetTickCount();
12303     while (GetTickCount() - time < 200) {
12304 	ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
12305         if (ret && msg.pt.x > x && msg.pt.y > y) break;
12306         if (!ret) MsgWaitForMultipleObjects( 0, NULL, FALSE, GetTickCount() - time, QS_ALLINPUT );
12307         else Sleep( GetTickCount() - time );
12308     }
12309 }
12310 
12311 #define STEP 5
12312 static void test_PeekMessage2(void)
12313 {
12314     HWND hwnd;
12315     BOOL ret;
12316     MSG msg;
12317     UINT message;
12318     DWORD time1, time2, time3;
12319     int x1, y1, x2, y2, x3, y3;
12320     POINT pos;
12321 
12322     time1 = time2 = time3 = 0;
12323     x1 = y1 = x2 = y2 = x3 = y3 = 0;
12324 
12325     /* Initialise window and make sure it is ready for events */
12326     hwnd = CreateWindowA("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
12327                         10, 10, 800, 800, NULL, NULL, NULL, NULL);
12328     assert(hwnd);
12329     trace("Window for test_PeekMessage2 %p\n", hwnd);
12330     ShowWindow(hwnd, SW_SHOW);
12331     UpdateWindow(hwnd);
12332     SetFocus(hwnd);
12333     GetCursorPos(&pos);
12334     SetCursorPos(100, 100);
12335     mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
12336     flush_events();
12337 
12338     /* Do initial mousemove, wait until we can see it
12339        and then do our test peek with PM_NOREMOVE. */
12340     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
12341     wait_move_event(hwnd, 100-STEP, 100-STEP);
12342 
12343     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
12344     if (!ret)
12345     {
12346         skip( "queuing mouse events not supported\n" );
12347         goto done;
12348     }
12349     else
12350     {
12351 	trace("1st move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
12352 	message = msg.message;
12353 	time1 = msg.time;
12354 	x1 = msg.pt.x;
12355 	y1 = msg.pt.y;
12356         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
12357     }
12358 
12359     /* Allow time to advance a bit, and then simulate the user moving their
12360      * mouse around. After that we peek again with PM_NOREMOVE.
12361      * Although the previous mousemove message was never removed, the
12362      * mousemove we now peek should reflect the recent mouse movements
12363      * because the input queue will merge the move events. */
12364     Sleep(100);
12365     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
12366     wait_move_event(hwnd, x1, y1);
12367 
12368     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
12369     ok(ret, "no message available\n");
12370     if (ret) {
12371 	trace("2nd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
12372 	message = msg.message;
12373 	time2 = msg.time;
12374 	x2 = msg.pt.x;
12375 	y2 = msg.pt.y;
12376         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
12377 	ok(time2 > time1, "message time not advanced: %x %x\n", time1, time2);
12378 	ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
12379     }
12380 
12381     /* Have another go, to drive the point home */
12382     Sleep(100);
12383     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
12384     wait_move_event(hwnd, x2, y2);
12385 
12386     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
12387     ok(ret, "no message available\n");
12388     if (ret) {
12389 	trace("3rd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
12390 	message = msg.message;
12391 	time3 = msg.time;
12392 	x3 = msg.pt.x;
12393 	y3 = msg.pt.y;
12394         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
12395 	ok(time3 > time2, "message time not advanced: %x %x\n", time2, time3);
12396 	ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
12397     }
12398 
12399 done:
12400     DestroyWindow(hwnd);
12401     SetCursorPos(pos.x, pos.y);
12402     flush_events();
12403 }
12404 
12405 static void test_PeekMessage3(void)
12406 {
12407     HWND hwnd;
12408     BOOL ret;
12409     MSG msg;
12410 
12411     hwnd = CreateWindowA("TestWindowClass", "PeekMessage3", WS_OVERLAPPEDWINDOW,
12412                          10, 10, 800, 800, NULL, NULL, NULL, NULL);
12413     ok(hwnd != NULL, "expected hwnd != NULL\n");
12414     flush_events();
12415 
12416     /* GetMessage() and PeekMessage(..., PM_REMOVE) should prefer messages which
12417      * were already seen. */
12418 
12419     SetTimer(hwnd, 1, 0, NULL);
12420     while (!PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE));
12421     ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12422     PostMessageA(hwnd, WM_USER, 0, 0);
12423     ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
12424     ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12425     ret = GetMessageA(&msg, NULL, 0, 0);
12426     ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12427     ret = GetMessageA(&msg, NULL, 0, 0);
12428     ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12429     ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12430     ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12431 
12432     SetTimer(hwnd, 1, 0, NULL);
12433     while (!PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE));
12434     ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12435     PostMessageA(hwnd, WM_USER, 0, 0);
12436     ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12437     ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12438     ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12439     ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12440     ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12441     ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12442 
12443     /* It doesn't matter if a message range is specified or not. */
12444 
12445     SetTimer(hwnd, 1, 0, NULL);
12446     while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12447     ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12448     PostMessageA(hwnd, WM_USER, 0, 0);
12449     ret = GetMessageA(&msg, NULL, 0, 0);
12450     ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12451     ret = GetMessageA(&msg, NULL, 0, 0);
12452     ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12453     ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12454     ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12455 
12456     /* But not if the post messages were added before the PeekMessage() call. */
12457 
12458     PostMessageA(hwnd, WM_USER, 0, 0);
12459     SetTimer(hwnd, 1, 0, NULL);
12460     while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12461     ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12462     ret = GetMessageA(&msg, NULL, 0, 0);
12463     ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12464     ret = GetMessageA(&msg, NULL, 0, 0);
12465     ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12466     ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12467     ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12468 
12469     /* More complicated test with multiple messages. */
12470 
12471     PostMessageA(hwnd, WM_USER, 0, 0);
12472     SetTimer(hwnd, 1, 0, NULL);
12473     while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12474     ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12475     PostMessageA(hwnd, WM_USER + 1, 0, 0);
12476     ret = GetMessageA(&msg, NULL, 0, 0);
12477     ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12478     ret = GetMessageA(&msg, NULL, 0, 0);
12479     ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12480     ret = GetMessageA(&msg, NULL, 0, 0);
12481     ok(ret && msg.message == WM_USER + 1, "msg.message = %u instead of WM_USER + 1\n", msg.message);
12482     ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12483     ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12484 
12485     /* Newer messages are still returned when specifying a message range. */
12486 
12487     SetTimer(hwnd, 1, 0, NULL);
12488     while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12489     ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12490     PostMessageA(hwnd, WM_USER + 1, 0, 0);
12491     PostMessageA(hwnd, WM_USER, 0, 0);
12492     ret = PeekMessageA(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
12493     ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12494     ret = PeekMessageA(&msg, NULL, WM_USER, WM_USER + 1, PM_NOREMOVE);
12495     ok(ret && msg.message == WM_USER + 1, "msg.message = %u instead of WM_USER + 1\n", msg.message);
12496     ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12497     ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12498     ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12499     ok(ret && msg.message == WM_USER + 1, "msg.message = %u instead of WM_USER + 1\n", msg.message);
12500     ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12501     ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12502     ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12503     ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12504 
12505     /* Also works for posted messages, but the situation is a bit different,
12506      * because both messages are in the same queue. */
12507 
12508     PostMessageA(hwnd, WM_TIMER, 0, 0);
12509     while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12510     ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12511     PostMessageA(hwnd, WM_USER, 0, 0);
12512     ret = GetMessageA(&msg, NULL, 0, 0);
12513     ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12514     ret = GetMessageA(&msg, NULL, 0, 0);
12515     ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12516     ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12517     ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12518 
12519     PostMessageA(hwnd, WM_USER, 0, 0);
12520     PostMessageA(hwnd, WM_TIMER, 0, 0);
12521     while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12522     ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12523     ret = GetMessageA(&msg, NULL, 0, 0);
12524     ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12525     ret = GetMessageA(&msg, NULL, 0, 0);
12526     ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12527     ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12528     ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12529 
12530     DestroyWindow(hwnd);
12531     flush_events();
12532 }
12533 
12534 static INT_PTR CALLBACK wm_quit_dlg_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
12535 {
12536     struct recvd_message msg;
12537 
12538     if (ignore_message( message )) return 0;
12539 
12540     msg.hwnd = hwnd;
12541     msg.message = message;
12542     msg.flags = sent|wparam|lparam;
12543     msg.wParam = wp;
12544     msg.lParam = lp;
12545     msg.descr = "dialog";
12546     add_message(&msg);
12547 
12548     switch (message)
12549     {
12550     case WM_INITDIALOG:
12551         PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
12552         PostMessageA(hwnd, WM_USER, 0xdead, 0xbeef);
12553         return 0;
12554 
12555     case WM_GETDLGCODE:
12556         return 0;
12557 
12558     case WM_USER:
12559         EndDialog(hwnd, 0);
12560         break;
12561     }
12562 
12563     return 1;
12564 }
12565 
12566 static const struct message WmQuitDialogSeq[] = {
12567     { HCBT_CREATEWND, hook },
12568     { WM_SETFONT, sent },
12569     { WM_INITDIALOG, sent },
12570     { WM_CHANGEUISTATE, sent|optional },
12571     { HCBT_DESTROYWND, hook },
12572     { 0x0090, sent|optional }, /* Vista */
12573     { WM_DESTROY, sent },
12574     { WM_NCDESTROY, sent },
12575     { 0 }
12576 };
12577 
12578 static const struct message WmStopQuitSeq[] = {
12579     { WM_DWMNCRENDERINGCHANGED, posted|optional },
12580     { WM_CLOSE, posted },
12581     { WM_QUIT, posted|wparam|lparam, 0x1234, 0 },
12582     { 0 }
12583 };
12584 
12585 static void test_quit_message(void)
12586 {
12587     MSG msg;
12588     BOOL ret;
12589 
12590     /* test using PostQuitMessage */
12591     flush_events();
12592     PostQuitMessage(0xbeef);
12593 
12594     msg.message = 0;
12595     ret = PeekMessageA(&msg, 0, 0, 0, PM_QS_SENDMESSAGE);
12596     ok(!ret, "got %x message\n", msg.message);
12597 
12598     ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
12599     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
12600     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12601     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
12602 
12603     ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
12604     ok(ret, "PostMessage failed with error %d\n", GetLastError());
12605 
12606     ret = GetMessageA(&msg, NULL, 0, 0);
12607     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
12608     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
12609 
12610     /* note: WM_QUIT message received after WM_USER message */
12611     ret = GetMessageA(&msg, NULL, 0, 0);
12612     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
12613     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12614     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
12615 
12616     ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12617     ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
12618 
12619     /* now test with PostThreadMessage - different behaviour! */
12620     PostThreadMessageA(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
12621 
12622     ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
12623     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
12624     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12625     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
12626 
12627     ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
12628     ok(ret, "PostMessage failed with error %d\n", GetLastError());
12629 
12630     /* note: we receive the WM_QUIT message first this time */
12631     ret = GetMessageA(&msg, NULL, 0, 0);
12632     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
12633     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12634     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
12635 
12636     ret = GetMessageA(&msg, NULL, 0, 0);
12637     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
12638     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
12639 
12640     flush_events();
12641     flush_sequence();
12642     ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, wm_quit_dlg_proc, 0);
12643     ok(ret == 1, "expected 1, got %d\n", ret);
12644     ok_sequence(WmQuitDialogSeq, "WmQuitDialogSeq", FALSE);
12645     memset(&msg, 0xab, sizeof(msg));
12646     ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12647     ok(ret, "PeekMessage failed\n");
12648     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12649     ok(msg.wParam == 0x1234, "wParam was 0x%lx instead of 0x1234\n", msg.wParam);
12650     ok(msg.lParam == 0, "lParam was 0x%lx instead of 0\n", msg.lParam);
12651 
12652     /* Check what happens to a WM_QUIT message posted to a window that gets
12653      * destroyed.
12654      */
12655     CreateWindowExA(0, "StopQuitClass", "Stop Quit Test", WS_OVERLAPPEDWINDOW,
12656                     0, 0, 100, 100, NULL, NULL, NULL, NULL);
12657     flush_sequence();
12658     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12659     {
12660         struct recvd_message rmsg;
12661         rmsg.hwnd = msg.hwnd;
12662         rmsg.message = msg.message;
12663         rmsg.flags = posted|wparam|lparam;
12664         rmsg.wParam = msg.wParam;
12665         rmsg.lParam = msg.lParam;
12666         rmsg.descr = "stop/quit";
12667         if (msg.message == WM_QUIT)
12668             /* The hwnd can only be checked here */
12669             ok(!msg.hwnd, "The WM_QUIT hwnd was %p instead of NULL\n", msg.hwnd);
12670         add_message(&rmsg);
12671         DispatchMessageA(&msg);
12672     }
12673     ok_sequence(WmStopQuitSeq, "WmStopQuitSeq", FALSE);
12674 }
12675 
12676 static const struct message WmNotifySeq[] = {
12677     { WM_NOTIFY, sent|wparam|lparam, 0x1234, 0xdeadbeef },
12678     { 0 }
12679 };
12680 
12681 static void test_notify_message(void)
12682 {
12683     HWND hwnd;
12684     BOOL ret;
12685     MSG msg;
12686 
12687     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
12688                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0, NULL, NULL, 0);
12689     ok(hwnd != 0, "Failed to create window\n");
12690     flush_events();
12691     flush_sequence();
12692 
12693     ret = SendNotifyMessageA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12694     ok(ret == TRUE, "SendNotifyMessageA failed with error %u\n", GetLastError());
12695     ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12696 
12697     ret = SendNotifyMessageW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12698     ok(ret == TRUE, "SendNotifyMessageW failed with error %u\n", GetLastError());
12699     ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12700 
12701     ret = SendMessageCallbackA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef, NULL, 0);
12702     ok(ret == TRUE, "SendMessageCallbackA failed with error %u\n", GetLastError());
12703     ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12704 
12705     ret = SendMessageCallbackW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef, NULL, 0);
12706     ok(ret == TRUE, "SendMessageCallbackW failed with error %u\n", GetLastError());
12707     ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12708 
12709     ret = PostMessageA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12710     ok(ret == TRUE, "PostMessageA failed with error %u\n", GetLastError());
12711     flush_events();
12712     ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12713 
12714     ret = PostMessageW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12715     ok(ret == TRUE, "PostMessageW failed with error %u\n", GetLastError());
12716     flush_events();
12717     ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12718 
12719     ret = PostThreadMessageA(GetCurrentThreadId(), WM_NOTIFY, 0x1234, 0xdeadbeef);
12720     ok(ret == TRUE, "PostThreadMessageA failed with error %u\n", GetLastError());
12721     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12722     {
12723         msg.hwnd = hwnd;
12724         DispatchMessageA(&msg);
12725     }
12726     ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12727 
12728     ret = PostThreadMessageW(GetCurrentThreadId(), WM_NOTIFY, 0x1234, 0xdeadbeef);
12729     ok(ret == TRUE, "PostThreadMessageW failed with error %u\n", GetLastError());
12730     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12731     {
12732         msg.hwnd = hwnd;
12733         DispatchMessageA(&msg);
12734     }
12735     ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12736 
12737     DestroyWindow(hwnd);
12738 }
12739 
12740 static const struct message WmMouseHoverSeq[] = {
12741     { WM_MOUSEACTIVATE, sent|optional },  /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
12742     { WM_MOUSEACTIVATE, sent|optional },
12743     { WM_TIMER, sent|optional }, /* XP sends it */
12744     { WM_SYSTIMER, sent },
12745     { WM_MOUSEHOVER, sent|wparam, 0 },
12746     { 0 }
12747 };
12748 
12749 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
12750 {
12751     MSG msg;
12752     DWORD start_ticks, end_ticks;
12753 
12754     start_ticks = GetTickCount();
12755     /* add some deviation (50%) to cover not expected delays */
12756     start_ticks += timeout / 2;
12757 
12758     do
12759     {
12760         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12761         {
12762             /* Timer proc messages are not dispatched to the window proc,
12763              * and therefore not logged.
12764              */
12765             if ((msg.message == WM_TIMER || msg.message == WM_SYSTIMER) && msg.hwnd)
12766             {
12767                 struct recvd_message s_msg;
12768 
12769                 s_msg.hwnd = msg.hwnd;
12770                 s_msg.message = msg.message;
12771                 s_msg.flags = sent|wparam|lparam;
12772                 s_msg.wParam = msg.wParam;
12773                 s_msg.lParam = msg.lParam;
12774                 s_msg.descr = "msg_loop";
12775                 add_message(&s_msg);
12776             }
12777             DispatchMessageA(&msg);
12778         }
12779 
12780         end_ticks = GetTickCount();
12781 
12782         /* inject WM_MOUSEMOVE to see how it changes tracking */
12783         if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
12784         {
12785             mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
12786             mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
12787 
12788             inject_mouse_move = FALSE;
12789         }
12790     } while (start_ticks + timeout >= end_ticks);
12791 }
12792 
12793 static void test_TrackMouseEvent(void)
12794 {
12795     TRACKMOUSEEVENT tme;
12796     BOOL ret;
12797     HWND hwnd, hchild;
12798     RECT rc_parent, rc_child;
12799     UINT default_hover_time, hover_width = 0, hover_height = 0;
12800 
12801 #define track_hover(track_hwnd, track_hover_time) \
12802     tme.cbSize = sizeof(tme); \
12803     tme.dwFlags = TME_HOVER; \
12804     tme.hwndTrack = track_hwnd; \
12805     tme.dwHoverTime = track_hover_time; \
12806     SetLastError(0xdeadbeef); \
12807     ret = pTrackMouseEvent(&tme); \
12808     ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
12809 
12810 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
12811     tme.cbSize = sizeof(tme); \
12812     tme.dwFlags = TME_QUERY; \
12813     tme.hwndTrack = (HWND)0xdeadbeef; \
12814     tme.dwHoverTime = 0xdeadbeef; \
12815     SetLastError(0xdeadbeef); \
12816     ret = pTrackMouseEvent(&tme); \
12817     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
12818     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
12819     ok(tme.dwFlags == (expected_track_flags), \
12820        "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
12821     ok(tme.hwndTrack == (expected_track_hwnd), \
12822        "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
12823     ok(tme.dwHoverTime == (expected_hover_time), \
12824        "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
12825 
12826 #define track_hover_cancel(track_hwnd) \
12827     tme.cbSize = sizeof(tme); \
12828     tme.dwFlags = TME_HOVER | TME_CANCEL; \
12829     tme.hwndTrack = track_hwnd; \
12830     tme.dwHoverTime = 0xdeadbeef; \
12831     SetLastError(0xdeadbeef); \
12832     ret = pTrackMouseEvent(&tme); \
12833     ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
12834 
12835     default_hover_time = 0xdeadbeef;
12836     SetLastError(0xdeadbeef);
12837     ret = SystemParametersInfoA(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
12838     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
12839        "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
12840     if (!ret) default_hover_time = 400;
12841     trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
12842 
12843     SetLastError(0xdeadbeef);
12844     ret = SystemParametersInfoA(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
12845     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
12846        "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
12847     if (!ret) hover_width = 4;
12848     SetLastError(0xdeadbeef);
12849     ret = SystemParametersInfoA(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
12850     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
12851        "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
12852     if (!ret) hover_height = 4;
12853     trace("hover rect is %u x %d\n", hover_width, hover_height);
12854 
12855     hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
12856 			  WS_OVERLAPPEDWINDOW | WS_VISIBLE,
12857 			  CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
12858 			  NULL, NULL, 0);
12859     assert(hwnd);
12860 
12861     hchild = CreateWindowExA(0, "TestWindowClass", NULL,
12862 			  WS_CHILD | WS_BORDER | WS_VISIBLE,
12863 			  50, 50, 200, 200, hwnd,
12864 			  NULL, NULL, 0);
12865     assert(hchild);
12866 
12867     SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
12868     flush_events();
12869     flush_sequence();
12870 
12871     tme.cbSize = 0;
12872     tme.dwFlags = TME_QUERY;
12873     tme.hwndTrack = (HWND)0xdeadbeef;
12874     tme.dwHoverTime = 0xdeadbeef;
12875     SetLastError(0xdeadbeef);
12876     ret = pTrackMouseEvent(&tme);
12877     ok(!ret, "TrackMouseEvent should fail\n");
12878     ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef),
12879        "not expected error %u\n", GetLastError());
12880 
12881     tme.cbSize = sizeof(tme);
12882     tme.dwFlags = TME_HOVER;
12883     tme.hwndTrack = (HWND)0xdeadbeef;
12884     tme.dwHoverTime = 0xdeadbeef;
12885     SetLastError(0xdeadbeef);
12886     ret = pTrackMouseEvent(&tme);
12887     ok(!ret, "TrackMouseEvent should fail\n");
12888     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
12889        "not expected error %u\n", GetLastError());
12890 
12891     tme.cbSize = sizeof(tme);
12892     tme.dwFlags = TME_HOVER | TME_CANCEL;
12893     tme.hwndTrack = (HWND)0xdeadbeef;
12894     tme.dwHoverTime = 0xdeadbeef;
12895     SetLastError(0xdeadbeef);
12896     ret = pTrackMouseEvent(&tme);
12897     ok(!ret, "TrackMouseEvent should fail\n");
12898     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
12899        "not expected error %u\n", GetLastError());
12900 
12901     GetWindowRect(hwnd, &rc_parent);
12902     GetWindowRect(hchild, &rc_child);
12903     SetCursorPos(rc_child.left - 10, rc_child.top - 10);
12904 
12905     /* Process messages so that the system updates its internal current
12906      * window and hittest, otherwise TrackMouseEvent calls don't have any
12907      * effect.
12908      */
12909     flush_events();
12910     flush_sequence();
12911 
12912     track_query(0, NULL, 0);
12913     track_hover(hchild, 0);
12914     track_query(0, NULL, 0);
12915 
12916     flush_events();
12917     flush_sequence();
12918 
12919     track_hover(hwnd, 0);
12920     tme.cbSize = sizeof(tme);
12921     tme.dwFlags = TME_QUERY;
12922     tme.hwndTrack = (HWND)0xdeadbeef;
12923     tme.dwHoverTime = 0xdeadbeef;
12924     SetLastError(0xdeadbeef);
12925     ret = pTrackMouseEvent(&tme);
12926     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());
12927     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize);
12928     if (!tme.dwFlags)
12929     {
12930         skip( "Cursor not inside window, skipping TrackMouseEvent tests\n" );
12931         DestroyWindow( hwnd );
12932         return;
12933     }
12934     ok(tme.dwFlags == TME_HOVER, "wrong tme.dwFlags %08x, expected TME_HOVER\n", tme.dwFlags);
12935     ok(tme.hwndTrack == hwnd, "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, hwnd);
12936     ok(tme.dwHoverTime == default_hover_time, "wrong tme.dwHoverTime %u, expected %u\n",
12937        tme.dwHoverTime, default_hover_time);
12938 
12939     pump_msg_loop_timeout(default_hover_time, FALSE);
12940     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
12941 
12942     track_query(0, NULL, 0);
12943 
12944     track_hover(hwnd, HOVER_DEFAULT);
12945     track_query(TME_HOVER, hwnd, default_hover_time);
12946 
12947     Sleep(default_hover_time / 2);
12948     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
12949     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
12950 
12951     track_query(TME_HOVER, hwnd, default_hover_time);
12952 
12953     pump_msg_loop_timeout(default_hover_time, FALSE);
12954     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
12955 
12956     track_query(0, NULL, 0);
12957 
12958     track_hover(hwnd, HOVER_DEFAULT);
12959     track_query(TME_HOVER, hwnd, default_hover_time);
12960 
12961     pump_msg_loop_timeout(default_hover_time, TRUE);
12962     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
12963 
12964     track_query(0, NULL, 0);
12965 
12966     track_hover(hwnd, HOVER_DEFAULT);
12967     track_query(TME_HOVER, hwnd, default_hover_time);
12968     track_hover_cancel(hwnd);
12969 
12970     DestroyWindow(hwnd);
12971 
12972 #undef track_hover
12973 #undef track_query
12974 #undef track_hover_cancel
12975 }
12976 
12977 
12978 static const struct message WmSetWindowRgn[] = {
12979     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
12980     { WM_NCCALCSIZE, sent|wparam, 1 },
12981     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
12982     { WM_GETTEXT, sent|defwinproc|optional },
12983     { WM_ERASEBKGND, sent|optional },
12984     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
12985     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12986     { 0 }
12987 };
12988 
12989 static const struct message WmSetWindowRgn_no_redraw[] = {
12990     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
12991     { WM_NCCALCSIZE, sent|wparam, 1 },
12992     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
12993     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12994     { 0 }
12995 };
12996 
12997 static const struct message WmSetWindowRgn_clear[] = {
12998     { WM_WINDOWPOSCHANGING, sent/*|wparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */ },
12999     { WM_NCCALCSIZE, sent|wparam, 1 },
13000     { WM_NCPAINT, sent|optional },
13001     { WM_GETTEXT, sent|defwinproc|optional },
13002     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
13003     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
13004     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
13005     { WM_NCPAINT, sent|optional },
13006     { WM_GETTEXT, sent|defwinproc|optional },
13007     { WM_ERASEBKGND, sent|optional },
13008     { WM_WINDOWPOSCHANGING, sent|optional },
13009     { WM_NCCALCSIZE, sent|optional|wparam, 1 },
13010     { WM_NCPAINT, sent|optional },
13011     { WM_GETTEXT, sent|defwinproc|optional },
13012     { WM_ERASEBKGND, sent|optional },
13013     { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
13014     { WM_NCCALCSIZE, sent|optional|wparam, 1 },
13015     { WM_NCPAINT, sent|optional },
13016     { WM_GETTEXT, sent|defwinproc|optional },
13017     { WM_ERASEBKGND, sent|optional },
13018     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
13019     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
13020     { 0 }
13021 };
13022 
13023 static void test_SetWindowRgn(void)
13024 {
13025     HRGN hrgn;
13026     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
13027                                 100, 100, 200, 200, 0, 0, 0, NULL);
13028     ok( hwnd != 0, "Failed to create overlapped window\n" );
13029 
13030     ShowWindow( hwnd, SW_SHOW );
13031     UpdateWindow( hwnd );
13032     flush_events();
13033     flush_sequence();
13034 
13035     trace("testing SetWindowRgn\n");
13036     hrgn = CreateRectRgn( 0, 0, 150, 150 );
13037     SetWindowRgn( hwnd, hrgn, TRUE );
13038     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
13039 
13040     hrgn = CreateRectRgn( 30, 30, 160, 160 );
13041     SetWindowRgn( hwnd, hrgn, FALSE );
13042     ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
13043 
13044     hrgn = CreateRectRgn( 0, 0, 180, 180 );
13045     SetWindowRgn( hwnd, hrgn, TRUE );
13046     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
13047 
13048     SetWindowRgn( hwnd, 0, TRUE );
13049     ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
13050 
13051     DestroyWindow( hwnd );
13052 }
13053 
13054 /*************************** ShowWindow() test ******************************/
13055 static const struct message WmShowNormal[] = {
13056     { WM_SHOWWINDOW, sent|wparam, 1 },
13057     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
13058     { HCBT_ACTIVATE, hook },
13059     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
13060     { HCBT_SETFOCUS, hook },
13061     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13062     { 0 }
13063 };
13064 static const struct message WmShow[] = {
13065     { WM_SHOWWINDOW, sent|wparam, 1 },
13066     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
13067     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13068     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13069     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13070     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13071     { 0 }
13072 };
13073 static const struct message WmShowNoActivate_1[] = {
13074     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
13075     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13076     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13077     { WM_MOVE, sent|defwinproc|optional },
13078     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
13079     { 0 }
13080 };
13081 static const struct message WmShowNoActivate_2[] = {
13082     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
13083     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
13084     { HCBT_ACTIVATE, hook|optional },
13085     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13086     { HCBT_SETFOCUS, hook|optional },
13087     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
13088     { WM_MOVE, sent|defwinproc },
13089     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
13090     { HCBT_SETFOCUS, hook|optional },
13091     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
13092     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
13093     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13094     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
13095     { 0 }
13096 };
13097 static const struct message WmShowNA_1[] = {
13098     { WM_SHOWWINDOW, sent|wparam, 1 },
13099     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13100     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13101     { 0 }
13102 };
13103 static const struct message WmShowNA_2[] = {
13104     { WM_SHOWWINDOW, sent|wparam, 1 },
13105     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13106     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13107     { 0 }
13108 };
13109 static const struct message WmRestore_1[] = {
13110     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
13111     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13112     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13113     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13114     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13115     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13116     { WM_MOVE, sent|defwinproc },
13117     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
13118     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
13119     { 0 }
13120 };
13121 static const struct message WmRestore_2[] = {
13122     { WM_SHOWWINDOW, sent|wparam, 1 },
13123     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
13124     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13125     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13126     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13127     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13128     { 0 }
13129 };
13130 static const struct message WmRestore_3[] = {
13131     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
13132     { WM_GETMINMAXINFO, sent },
13133     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13134     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
13135     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
13136     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
13137     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13138     { WM_MOVE, sent|defwinproc },
13139     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
13140     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
13141     { 0 }
13142 };
13143 static const struct message WmRestore_4[] = {
13144     { HCBT_MINMAX, hook|lparam|optional, 0, SW_RESTORE },
13145     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13146     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13147     { WM_MOVE, sent|defwinproc|optional },
13148     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
13149     { 0 }
13150 };
13151 static const struct message WmRestore_5[] = {
13152     { HCBT_MINMAX, hook|lparam|optional, 0, SW_SHOWNORMAL },
13153     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13154     { HCBT_ACTIVATE, hook|optional },
13155     { HCBT_SETFOCUS, hook|optional },
13156     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13157     { WM_MOVE, sent|defwinproc|optional },
13158     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
13159     { 0 }
13160 };
13161 static const struct message WmHide_1[] = {
13162     { WM_SHOWWINDOW, sent|wparam, 0 },
13163     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOACTIVATE },
13164     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOACTIVATE },
13165     { HCBT_ACTIVATE, hook|optional },
13166     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
13167     { 0 }
13168 };
13169 static const struct message WmHide_2[] = {
13170     { WM_SHOWWINDOW, sent|wparam, 0 },
13171     { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
13172     { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
13173     { HCBT_ACTIVATE, hook|optional },
13174     { 0 }
13175 };
13176 static const struct message WmHide_3[] = {
13177     { WM_SHOWWINDOW, sent|wparam, 0 },
13178     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
13179     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13180     { HCBT_SETFOCUS, hook|optional },
13181     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
13182     { 0 }
13183 };
13184 static const struct message WmShowMinimized_1[] = {
13185     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
13186     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13187     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13188     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13189     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13190     { WM_MOVE, sent|defwinproc },
13191     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
13192     { 0 }
13193 };
13194 static const struct message WmMinimize_1[] = {
13195     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
13196     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13197     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
13198     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13199     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13200     { WM_MOVE, sent|defwinproc },
13201     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
13202     { 0 }
13203 };
13204 static const struct message WmMinimize_2[] = {
13205     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
13206     { HCBT_SETFOCUS, hook|optional },
13207     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
13208     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
13209     { WM_MOVE, sent|defwinproc },
13210     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
13211     { 0 }
13212 };
13213 static const struct message WmMinimize_3[] = {
13214     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
13215     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
13216     { HCBT_ACTIVATE, hook|optional },
13217     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13218     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
13219     { WM_MOVE, sent|defwinproc },
13220     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
13221     { 0 }
13222 };
13223 static const struct message WmShowMinNoActivate[] = {
13224     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
13225     { WM_WINDOWPOSCHANGING, sent },
13226     { WM_WINDOWPOSCHANGED, sent },
13227     { WM_MOVE, sent|defwinproc|optional },
13228     { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
13229     { 0 }
13230 };
13231 static const struct message WmMinMax_1[] = {
13232     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
13233     { 0 }
13234 };
13235 static const struct message WmMinMax_2[] = {
13236     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
13237     { WM_GETMINMAXINFO, sent|optional },
13238     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED },
13239     { HCBT_ACTIVATE, hook|optional },
13240     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13241     { HCBT_SETFOCUS, hook|optional },
13242     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13243     { WM_MOVE, sent|defwinproc|optional },
13244     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MAXIMIZED },
13245     { HCBT_SETFOCUS, hook|optional },
13246     { 0 }
13247 };
13248 static const struct message WmMinMax_3[] = {
13249     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
13250     { HCBT_SETFOCUS, hook|optional },
13251     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13252     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13253     { WM_MOVE, sent|defwinproc|optional },
13254     { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
13255     { 0 }
13256 };
13257 static const struct message WmMinMax_4[] = {
13258     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
13259     { 0 }
13260 };
13261 static const struct message WmShowMaximized_1[] = {
13262     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
13263     { WM_GETMINMAXINFO, sent },
13264     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13265     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13266     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13267     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13268     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13269     { WM_MOVE, sent|defwinproc },
13270     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
13271     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
13272     { 0 }
13273 };
13274 static const struct message WmShowMaximized_2[] = {
13275     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
13276     { WM_GETMINMAXINFO, sent },
13277     { WM_WINDOWPOSCHANGING, sent|optional },
13278     { HCBT_ACTIVATE, hook|optional },
13279     { WM_WINDOWPOSCHANGED, sent|optional },
13280     { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
13281     { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
13282     { WM_WINDOWPOSCHANGING, sent|optional },
13283     { HCBT_SETFOCUS, hook|optional },
13284     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13285     { WM_MOVE, sent|defwinproc },
13286     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
13287     { HCBT_SETFOCUS, hook|optional },
13288     { 0 }
13289 };
13290 static const struct message WmShowMaximized_3[] = {
13291     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
13292     { WM_GETMINMAXINFO, sent|optional },
13293     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13294     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13295     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13296     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13297     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13298     { WM_MOVE, sent|defwinproc|optional },
13299     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
13300     { 0 }
13301 };
13302 
13303 static void test_ShowWindow(void)
13304 {
13305     /* ShowWindow commands in random order */
13306     static const struct
13307     {
13308         INT cmd; /* ShowWindow command */
13309         LPARAM ret; /* ShowWindow return value */
13310         DWORD style; /* window style after the command */
13311         const struct message *msg; /* message sequence the command produces */
13312         INT wp_cmd, wp_flags; /* window placement after the command */
13313         POINT wp_min, wp_max; /* window placement after the command */
13314         BOOL todo_msg; /* message sequence doesn't match what Wine does */
13315     } sw[] =
13316     {
13317 /*  1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal,
13318            SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
13319 /*  2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq,
13320            SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
13321 /*  3 */ { SW_HIDE, TRUE, 0, WmHide_1,
13322            SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
13323 /*  4 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13324            SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
13325 /*  5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1,
13326            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13327 /*  6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1,
13328            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13329 /*  7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1,
13330            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13331 /*  8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
13332            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13333 /*  9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1,
13334            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13335 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
13336            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13337 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1,
13338            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13339 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq,
13340            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13341 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1,
13342            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13343 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
13344            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13345 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2,
13346            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13347 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13348            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13349 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow,
13350            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13351 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
13352            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13353 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
13354            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13355 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
13356            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13357 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13358            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13359 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate,
13360            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, TRUE },
13361 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4,
13362            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13363 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13364            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13365 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
13366            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13367 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1,
13368            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13369 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2,
13370            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13371 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13372            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13373 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
13374            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13375 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1,
13376            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13377 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
13378            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13379 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3,
13380            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13381 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13382            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13383 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, /* what does this mean?! */
13384            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13385 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq,
13386            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13387 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13388            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13389 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2,
13390            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13391 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
13392            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13393 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
13394            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13395 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2,
13396            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13397 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
13398            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13399 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2,
13400            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13401 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
13402            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13403 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
13404            SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13405 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
13406            SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13407 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3,
13408            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13409 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4,
13410            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13411 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3,
13412            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13413 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq,
13414            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13415 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
13416            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13417 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
13418            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13419 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1,
13420            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13421 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13422            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13423 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3,
13424            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13425 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13426            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13427 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2,
13428            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13429 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
13430            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE }
13431     };
13432     HWND hwnd;
13433     DWORD style;
13434     LPARAM ret;
13435     INT i;
13436     WINDOWPLACEMENT wp;
13437     RECT win_rc, work_rc = {0, 0, 0, 0};
13438 
13439 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
13440     hwnd = CreateWindowExA(0, "ShowWindowClass", NULL, WS_BASE,
13441                           120, 120, 90, 90,
13442                           0, 0, 0, NULL);
13443     assert(hwnd);
13444 
13445     style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
13446     ok(style == 0, "expected style 0, got %08x\n", style);
13447 
13448     flush_events();
13449     flush_sequence();
13450 
13451     if (pGetMonitorInfoA && pMonitorFromPoint)
13452     {
13453         HMONITOR hmon;
13454         MONITORINFO mi;
13455         POINT pt = {0, 0};
13456 
13457         SetLastError(0xdeadbeef);
13458         hmon = pMonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
13459         ok(hmon != 0, "MonitorFromPoint error %u\n", GetLastError());
13460 
13461         mi.cbSize = sizeof(mi);
13462         SetLastError(0xdeadbeef);
13463         ret = pGetMonitorInfoA(hmon, &mi);
13464         ok(ret, "GetMonitorInfo error %u\n", GetLastError());
13465         trace("monitor %s, work %s\n", wine_dbgstr_rect(&mi.rcMonitor),
13466               wine_dbgstr_rect(&mi.rcWork));
13467         work_rc = mi.rcWork;
13468     }
13469 
13470     GetWindowRect(hwnd, &win_rc);
13471     OffsetRect(&win_rc, -work_rc.left, -work_rc.top);
13472 
13473     wp.length = sizeof(wp);
13474     SetLastError(0xdeadbeaf);
13475     ret = GetWindowPlacement(hwnd, &wp);
13476     ok(ret, "GetWindowPlacement error %u\n", GetLastError());
13477     ok(wp.flags == 0, "expected 0, got %#x\n", wp.flags);
13478     ok(wp.showCmd == SW_SHOWNORMAL, "expected SW_SHOWNORMAL, got %d\n", wp.showCmd);
13479     ok(wp.ptMinPosition.x == -1 && wp.ptMinPosition.y == -1,
13480        "expected -1,-1 got %d,%d\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
13481     ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
13482        "expected -1,-1 got %d,%d\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
13483     todo_wine_if (work_rc.left || work_rc.top) /* FIXME: remove once Wine is fixed */
13484     ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n", wine_dbgstr_rect(&win_rc),
13485        wine_dbgstr_rect(&wp.rcNormalPosition));
13486 
13487     for (i = 0; i < ARRAY_SIZE(sw); i++)
13488     {
13489         static const char * const sw_cmd_name[13] =
13490         {
13491             "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
13492             "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
13493             "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
13494             "SW_NORMALNA" /* 0xCC */
13495         };
13496         char comment[64];
13497         INT idx; /* index into the above array of names */
13498 
13499         idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
13500 
13501         style = GetWindowLongA(hwnd, GWL_STYLE);
13502         trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
13503         ret = ShowWindow(hwnd, sw[i].cmd);
13504         ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
13505         style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
13506         ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
13507 
13508         sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
13509         ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
13510 
13511         wp.length = sizeof(wp);
13512         SetLastError(0xdeadbeaf);
13513         ret = GetWindowPlacement(hwnd, &wp);
13514         ok(ret, "GetWindowPlacement error %u\n", GetLastError());
13515         ok(wp.flags == sw[i].wp_flags, "expected %#x, got %#x\n", sw[i].wp_flags, wp.flags);
13516         ok(wp.showCmd == sw[i].wp_cmd, "expected %d, got %d\n", sw[i].wp_cmd, wp.showCmd);
13517 
13518         /* NT moves the minimized window to -32000,-32000, win9x to 3000,3000 */
13519         if ((wp.ptMinPosition.x + work_rc.left == -32000 && wp.ptMinPosition.y + work_rc.top == -32000) ||
13520             (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000))
13521         {
13522             ok((wp.ptMinPosition.x + work_rc.left == sw[i].wp_min.x && wp.ptMinPosition.y + work_rc.top == sw[i].wp_min.y) ||
13523                (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000),
13524                "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
13525         }
13526         else
13527         {
13528             ok(wp.ptMinPosition.x == sw[i].wp_min.x && wp.ptMinPosition.y == sw[i].wp_min.y,
13529                "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
13530         }
13531 
13532         todo_wine_if(wp.ptMaxPosition.x != sw[i].wp_max.x || wp.ptMaxPosition.y != sw[i].wp_max.y)
13533         ok(wp.ptMaxPosition.x == sw[i].wp_max.x && wp.ptMaxPosition.y == sw[i].wp_max.y,
13534            "expected %d,%d got %d,%d\n", sw[i].wp_max.x, sw[i].wp_max.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y);
13535 
13536 if (0) /* FIXME: Wine behaves completely different here */
13537         ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n",
13538            wine_dbgstr_rect(&win_rc), wine_dbgstr_rect(&wp.rcNormalPosition));
13539     }
13540     DestroyWindow(hwnd);
13541     flush_events();
13542 }
13543 
13544 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13545 {
13546     struct recvd_message msg;
13547 
13548     if (ignore_message( message )) return 0;
13549 
13550     msg.hwnd = hwnd;
13551     msg.message = message;
13552     msg.flags = sent|wparam|lparam;
13553     msg.wParam = wParam;
13554     msg.lParam = lParam;
13555     msg.descr = "dialog";
13556     add_message(&msg);
13557 
13558     /* calling DefDlgProc leads to a recursion under XP */
13559 
13560     switch (message)
13561     {
13562     case WM_INITDIALOG:
13563         return lParam;
13564 
13565     case WM_GETDLGCODE:
13566         return 0;
13567     }
13568     return 1;
13569 }
13570 
13571 static WNDPROC orig_edit_proc;
13572 static LRESULT WINAPI dlg_creation_edit_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
13573 {
13574     struct recvd_message msg;
13575 
13576     if (ignore_message( message )) return 0;
13577 
13578     msg.hwnd = hwnd;
13579     msg.message = message;
13580     msg.flags = sent|wparam|lparam;
13581     msg.wParam = wp;
13582     msg.lParam = lp;
13583     msg.descr = "edit";
13584     add_message(&msg);
13585 
13586     return CallWindowProcW(orig_edit_proc, hwnd, message, wp, lp);
13587 }
13588 
13589 static INT_PTR WINAPI test_dlg_proc2(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13590 {
13591     struct recvd_message msg;
13592 
13593     if (ignore_message( message )) return 0;
13594 
13595     msg.hwnd = hwnd;
13596     msg.message = message;
13597     msg.flags = sent|wparam|lparam|parent;
13598     msg.wParam = wParam;
13599     msg.lParam = lParam;
13600     msg.descr = "dialog";
13601     add_message(&msg);
13602 
13603     if (message == WM_INITDIALOG)
13604     {
13605         orig_edit_proc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hwnd, 200),
13606                 GWLP_WNDPROC, (LONG_PTR)dlg_creation_edit_proc);
13607     }
13608 
13609     return 1;
13610 }
13611 
13612 static INT_PTR WINAPI test_dlg_proc3(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13613 {
13614     ok( 0, "should not be called since DefDlgProc is not used\n" );
13615     return 0;
13616 }
13617 
13618 static LRESULT WINAPI test_dlg_proc4(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13619 {
13620     struct recvd_message msg;
13621 
13622     if (!ignore_message( message ))
13623     {
13624         msg.hwnd = hwnd;
13625         msg.message = message;
13626         msg.flags = sent|wparam|lparam|parent;
13627         msg.wParam = wParam;
13628         msg.lParam = lParam;
13629         msg.descr = "dialog";
13630         add_message(&msg);
13631     }
13632     if (message == WM_INITDIALOG)
13633     {
13634         orig_edit_proc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hwnd, 200),
13635                 GWLP_WNDPROC, (LONG_PTR)dlg_creation_edit_proc);
13636         return 1;
13637     }
13638     return DefWindowProcW( hwnd, message, wParam, lParam );
13639 }
13640 
13641 static const struct message WmDefDlgSetFocus_1[] = {
13642     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13643     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
13644     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
13645     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
13646     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
13647     { HCBT_SETFOCUS, hook },
13648     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
13649     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13650     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
13651     { WM_SETFOCUS, sent|wparam, 0 },
13652     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
13653     { WM_CTLCOLOREDIT, sent },
13654     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
13655     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13656     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13657     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13658     { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
13659     { 0 }
13660 };
13661 static const struct message WmDefDlgSetFocus_2[] = {
13662     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13663     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
13664     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
13665     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
13666     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
13667     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13668     { WM_CTLCOLOREDIT, sent|optional }, /* XP */
13669     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13670     { 0 }
13671 };
13672 /* Creation of a dialog */
13673 static const struct message WmCreateDialogParamSeq_0[] = {
13674     { HCBT_CREATEWND, hook },
13675     { WM_NCCREATE, sent },
13676     { WM_NCCALCSIZE, sent|wparam, 0 },
13677     { WM_CREATE, sent },
13678     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13679     { WM_SIZE, sent|wparam, SIZE_RESTORED },
13680     { WM_MOVE, sent },
13681     { WM_SETFONT, sent },
13682     { WM_INITDIALOG, sent },
13683     { WM_CHANGEUISTATE, sent|optional },
13684     { 0 }
13685 };
13686 /* Creation of a dialog */
13687 static const struct message WmCreateDialogParamSeq_1[] = {
13688     { HCBT_CREATEWND, hook },
13689     { WM_NCCREATE, sent },
13690     { WM_NCCALCSIZE, sent|wparam, 0 },
13691     { WM_CREATE, sent },
13692     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13693     { WM_SIZE, sent|wparam, SIZE_RESTORED },
13694     { WM_MOVE, sent },
13695     { WM_SETFONT, sent },
13696     { WM_INITDIALOG, sent },
13697     { WM_GETDLGCODE, sent|wparam|lparam|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
13698     { HCBT_SETFOCUS, hook },
13699     { HCBT_ACTIVATE, hook },
13700     { WM_QUERYNEWPALETTE, sent|optional },
13701     { WM_PALETTEISCHANGING, sent|optional },
13702     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13703     { WM_ACTIVATEAPP, sent|wparam, 1 },
13704     { WM_NCACTIVATE, sent },
13705     { WM_ACTIVATE, sent|wparam, 1 },
13706     { WM_SETFOCUS, sent },
13707     { WM_CHANGEUISTATE, sent|optional },
13708     { 0 }
13709 };
13710 /* Creation of a dialog */
13711 static const struct message WmCreateDialogParamSeq_2[] = {
13712     { HCBT_CREATEWND, hook },
13713     { WM_NCCREATE, sent },
13714     { WM_NCCALCSIZE, sent|wparam, 0 },
13715     { WM_CREATE, sent },
13716     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13717     { WM_SIZE, sent|wparam, SIZE_RESTORED },
13718     { WM_MOVE, sent },
13719     { WM_CHANGEUISTATE, sent|optional },
13720     { 0 }
13721 };
13722 
13723 static const struct message WmCreateDialogParamSeq_3[] = {
13724     { HCBT_CREATEWND, hook },
13725     { WM_SETFONT, sent|parent },
13726     { WM_INITDIALOG, sent|parent },
13727     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13728     { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
13729     { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13730     { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13731     { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13732     { HCBT_ACTIVATE, hook },
13733     { WM_QUERYNEWPALETTE, sent|parent|optional }, /* TODO: this message should not be sent */
13734     { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13735     { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13736     { WM_WINDOWPOSCHANGED, sent|parent|wparam|optional, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13737     { WM_WINDOWPOSCHANGED, sent|parent|wparam|optional, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13738     { WM_ACTIVATEAPP, sent|parent|wparam, 1 },
13739     { WM_NCACTIVATE, sent|parent },
13740     { WM_ACTIVATE, sent|parent|wparam, 1 },
13741     { WM_SETFOCUS, sent },
13742     { WM_COMMAND, sent|parent|wparam, MAKELONG(200, EN_SETFOCUS) },
13743     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13744     { WM_USER, sent|parent },
13745     { WM_CHANGEUISTATE, sent|parent|optional },
13746     { 0 }
13747 };
13748 
13749 static const struct message WmCreateDialogParamSeq_4[] = {
13750     { HCBT_CREATEWND, hook },
13751     { WM_NCCREATE, sent|parent },
13752     { WM_NCCALCSIZE, sent|parent|wparam, 0 },
13753     { WM_CREATE, sent|parent },
13754     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13755     { WM_SIZE, sent|parent|wparam, SIZE_RESTORED },
13756     { WM_MOVE, sent|parent },
13757     { WM_SETFONT, sent|parent },
13758     { WM_INITDIALOG, sent|parent },
13759     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13760     { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
13761     { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13762     { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13763     { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13764     { HCBT_ACTIVATE, hook },
13765     { WM_QUERYNEWPALETTE, sent|parent|optional }, /* TODO: this message should not be sent */
13766     { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13767     { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13768     { WM_ACTIVATEAPP, sent|parent|wparam, 1 },
13769     { WM_NCACTIVATE, sent|parent },
13770     { WM_ACTIVATE, sent|parent|wparam, 1 },
13771     { HCBT_SETFOCUS, hook },
13772     { WM_SETFOCUS, sent|parent },
13773     { WM_KILLFOCUS, sent|parent },
13774     { WM_SETFOCUS, sent },
13775     { WM_COMMAND, sent|parent|wparam, MAKELONG(200, EN_SETFOCUS) },
13776     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13777     { WM_USER, sent|parent },
13778     { WM_CHANGEUISTATE, sent|parent|optional },
13779     { WM_UPDATEUISTATE, sent|parent|optional },
13780     { WM_UPDATEUISTATE, sent|optional },
13781     { 0 }
13782 };
13783 
13784 static void test_dialog_messages(void)
13785 {
13786     WNDCLASSA cls;
13787     HWND hdlg, hedit1, hedit2, hfocus, parent, child, child2;
13788     LRESULT ret;
13789 
13790 #define set_selection(hctl, start, end) \
13791     ret = SendMessageA(hctl, EM_SETSEL, start, end); \
13792     ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
13793 
13794 #define check_selection(hctl, start, end) \
13795     ret = SendMessageA(hctl, EM_GETSEL, 0, 0); \
13796     ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
13797 
13798     subclass_edit();
13799 
13800     hdlg = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
13801                           WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
13802                           0, 0, 100, 100, 0, 0, 0, NULL);
13803     ok(hdlg != 0, "Failed to create custom dialog window\n");
13804 
13805     hedit1 = CreateWindowExA(0, "my_edit_class", NULL,
13806                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
13807                            0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
13808     ok(hedit1 != 0, "Failed to create edit control\n");
13809     hedit2 = CreateWindowExA(0, "my_edit_class", NULL,
13810                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
13811                            0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
13812     ok(hedit2 != 0, "Failed to create edit control\n");
13813 
13814     SendMessageA(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
13815     SendMessageA(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
13816 
13817     hfocus = GetFocus();
13818     ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
13819 
13820     SetFocus(hedit2);
13821     hfocus = GetFocus();
13822     ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
13823 
13824     check_selection(hedit1, 0, 0);
13825     check_selection(hedit2, 0, 0);
13826 
13827     set_selection(hedit2, 0, -1);
13828     check_selection(hedit2, 0, 3);
13829 
13830     SetFocus(0);
13831     hfocus = GetFocus();
13832     ok(hfocus == 0, "wrong focus %p\n", hfocus);
13833 
13834     flush_sequence();
13835     ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
13836     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
13837     ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
13838 
13839     hfocus = GetFocus();
13840     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
13841 
13842     check_selection(hedit1, 0, 5);
13843     check_selection(hedit2, 0, 3);
13844 
13845     flush_sequence();
13846     ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
13847     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
13848     ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
13849 
13850     hfocus = GetFocus();
13851     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
13852 
13853     check_selection(hedit1, 0, 5);
13854     check_selection(hedit2, 0, 3);
13855 
13856     EndDialog(hdlg, 0);
13857     DestroyWindow(hedit1);
13858     DestroyWindow(hedit2);
13859     DestroyWindow(hdlg);
13860     flush_sequence();
13861 
13862 #undef set_selection
13863 #undef check_selection
13864 
13865     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
13866     cls.lpszClassName = "MyDialogClass";
13867     cls.hInstance = GetModuleHandleA(NULL);
13868     /* need a cast since a dlgproc is used as a wndproc */
13869     cls.lpfnWndProc = test_dlg_proc;
13870     if (!RegisterClassA(&cls)) assert(0);
13871 
13872     SetFocus(0);
13873     flush_sequence();
13874     hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
13875     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13876     ok_sequence(WmCreateDialogParamSeq_0, "CreateDialogParam_0", FALSE);
13877     hfocus = GetFocus();
13878     ok(hfocus == 0, "wrong focus %p\n", hfocus);
13879     EndDialog(hdlg, 0);
13880     DestroyWindow(hdlg);
13881     flush_sequence();
13882 
13883     SetFocus(0);
13884     flush_sequence();
13885     hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 1);
13886     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13887     ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
13888     hfocus = GetFocus();
13889     ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
13890     EndDialog(hdlg, 0);
13891     DestroyWindow(hdlg);
13892     flush_sequence();
13893 
13894     hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
13895     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13896     ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
13897     EndDialog(hdlg, 0);
13898     DestroyWindow(hdlg);
13899     flush_sequence();
13900 
13901     hdlg = CreateDialogParamA(0, "FOCUS_TEST_DIALOG_3", 0, test_dlg_proc2, 0);
13902     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13903     ok_sequence(WmCreateDialogParamSeq_3, "CreateDialogParam_3", TRUE);
13904     EndDialog(hdlg, 0);
13905     DestroyWindow(hdlg);
13906     flush_sequence();
13907 
13908     UnregisterClassA( cls.lpszClassName, cls.hInstance );
13909     cls.lpfnWndProc = test_dlg_proc4;
13910     ok( RegisterClassA(&cls), "failed to register class again\n" );
13911     hdlg = CreateDialogParamA(0, "FOCUS_TEST_DIALOG_4", 0, test_dlg_proc3, 0);
13912     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13913     ok_sequence(WmCreateDialogParamSeq_4, "CreateDialogParam_4", TRUE);
13914     EndDialog(hdlg, 0);
13915     DestroyWindow(hdlg);
13916     flush_sequence();
13917 
13918     UnregisterClassA(cls.lpszClassName, cls.hInstance);
13919 
13920     parent = CreateWindowExA(0, "TestParentClass", "Test parent",
13921                              WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13922                              100, 100, 200, 200, 0, 0, 0, NULL);
13923     ok (parent != 0, "Failed to create parent window\n");
13924 
13925     /* This child has no parent set. We will later call SetParent on it,
13926      * so that it will have a parent set, but no WS_CHILD style. */
13927     child = CreateWindowExA(0, "TestWindowClass", "Test child",
13928                             WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13929                             100, 100, 200, 200, 0, 0, 0, NULL);
13930     ok (child != 0, "Failed to create child window\n");
13931 
13932     /* This is a regular child window. When used as an owner, the other
13933      * child window will be used. */
13934     child2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2",
13935                              WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CHILD,
13936                              100, 100, 200, 200, child, 0, 0, NULL);
13937     ok (child2 != 0, "Failed to create child window\n");
13938 
13939     SetParent(child, parent);
13940     SetFocus(child);
13941 
13942     flush_sequence();
13943     DialogBoxA( 0, "TEST_DIALOG", child2, TestModalDlgProc2 );
13944     ok_sequence(WmModalDialogSeq_2, "ModalDialog2", TRUE);
13945 
13946     DestroyWindow(child2);
13947     DestroyWindow(child);
13948     DestroyWindow(parent);
13949     flush_sequence();
13950 }
13951 
13952 static void test_enddialog_seq(HWND dialog, HWND owner)
13953 {
13954     const struct message seq[] = {
13955         { WM_ENABLE, sent },
13956         { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13957         { HCBT_ACTIVATE, hook|wparam, (WPARAM)owner },
13958         { WM_NCACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13959         { WM_ACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13960         /* FIXME: Following two are optional because Wine sends WM_QUERYNEWPALETTE instead of WM_WINDOWPOSCHANGING */
13961         { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13962         { WM_QUERYNEWPALETTE, sent|optional },
13963         { WM_NCACTIVATE, sent|wparam|lparam, WA_ACTIVE, (LPARAM)dialog },
13964         { WM_GETTEXT, sent|optional|defwinproc },
13965         { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, (LPARAM)dialog },
13966         { HCBT_SETFOCUS, hook|wparam, (WPARAM)owner },
13967         { WM_KILLFOCUS, sent|wparam, (WPARAM)owner },
13968         { WM_SETFOCUS, sent|defwinproc|wparam, (WPARAM)dialog },
13969         { 0 }
13970     };
13971 
13972     flush_sequence();
13973     EndDialog(dialog, 0);
13974     ok_sequence(seq, "EndDialog", FALSE);
13975 }
13976 
13977 static void test_enddialog_seq2(HWND dialog, HWND owner)
13978 {
13979     const struct message seq[] = {
13980         { WM_ENABLE, parent|sent },
13981         { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13982         { HCBT_ACTIVATE, hook|wparam, (WPARAM)owner },
13983         { WM_NCACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13984         { WM_ACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13985         { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13986         { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13987         { HCBT_SETFOCUS, hook|wparam, (WPARAM)owner },
13988         { WM_KILLFOCUS, sent|wparam, (WPARAM)owner },
13989         { WM_SETFOCUS, sent|parent|defwinproc|wparam, (WPARAM)dialog },
13990         { 0 }
13991     };
13992 
13993     flush_sequence();
13994     EndDialog(dialog, 0);
13995     ok_sequence(seq, "EndDialog2", FALSE);
13996 }
13997 
13998 static void test_EndDialog(void)
13999 {
14000     HWND hparent, hother, hactive, hdlg, hchild;
14001     WNDCLASSA cls;
14002 
14003     hparent = CreateWindowExA(0, "TestParentClass", "Test parent",
14004                               WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_DISABLED,
14005                               100, 100, 200, 200, 0, 0, 0, NULL);
14006     ok (hparent != 0, "Failed to create parent window\n");
14007 
14008     hother = CreateWindowExA(0, "TestParentClass", "Test parent 2",
14009                               WS_OVERLAPPEDWINDOW | WS_VISIBLE,
14010                               200, 100, 200, 200, 0, 0, 0, NULL);
14011     ok (hother != 0, "Failed to create parent window\n");
14012 
14013     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
14014     cls.lpszClassName = "MyDialogClass";
14015     cls.hInstance = GetModuleHandleA(NULL);
14016     cls.lpfnWndProc = test_dlg_proc;
14017     if (!RegisterClassA(&cls)) assert(0);
14018 
14019     flush_sequence();
14020     SetForegroundWindow(hother);
14021     hactive = GetForegroundWindow();
14022     ok(hother == hactive, "Wrong window has focus (%p != %p)\n", hother, hactive);
14023 
14024     /* create a dialog where the parent is disabled, this parent should be
14025      * enabled and receive focus when dialog exits */
14026     hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hparent, test_dlg_proc, 0);
14027     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
14028     SetForegroundWindow(hdlg);
14029     hactive = GetForegroundWindow();
14030     ok(hdlg == hactive, "Wrong window has focus (%p != %p)\n", hdlg, hactive);
14031     EndDialog(hdlg, 0);
14032     ok(IsWindowEnabled(hparent), "parent is not enabled\n");
14033     hactive = GetForegroundWindow();
14034     ok(hparent == hactive, "Wrong window has focus (parent != active) (active: %p, parent: %p, dlg: %p, other: %p)\n", hactive, hparent, hdlg, hother);
14035     DestroyWindow(hdlg);
14036     flush_sequence();
14037 
14038     /* create a dialog where the parent is disabled and set active window to other window before calling EndDialog */
14039     EnableWindow(hparent, FALSE);
14040     hdlg = CreateWindowExA(0, "TestDialogClass", NULL,
14041                           WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
14042                           0, 0, 100, 100, hparent, 0, 0, NULL);
14043     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
14044     flush_sequence();
14045     SetForegroundWindow(hother);
14046     flush_sequence();
14047     hactive = GetForegroundWindow();
14048     ok(hactive == hother, "Wrong foreground (%p != %p)\n", hactive, hother);
14049     hactive = GetActiveWindow();
14050     ok(hactive == hother, "Wrong active window (%p != %p)\n", hactive, hother);
14051     EndDialog(hdlg, 0);
14052     ok(IsWindowEnabled(hparent), "parent is not enabled\n");
14053     hactive = GetForegroundWindow();
14054     ok(hother == hactive, "Wrong window has focus (other != active) (active: %p, parent: %p, dlg: %p, other: %p)\n", hactive, hparent, hdlg, hother);
14055     DestroyWindow(hdlg);
14056     flush_sequence();
14057 
14058     DestroyWindow( hparent );
14059 
14060     hparent = CreateWindowExA(0, "TestParentClass", "Test parent",
14061                               WS_POPUP | WS_VISIBLE | WS_DISABLED,
14062                               100, 100, 200, 200, 0, 0, 0, NULL);
14063     ok (hparent != 0, "Failed to create parent window\n");
14064 
14065     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
14066                              WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_DISABLED,
14067                              0, 0, 0, 0, 0, 0, 0, NULL);
14068     ok (hchild != 0, "Failed to create child window\n");
14069 
14070     SetParent(hchild, hparent);
14071 
14072     flush_sequence();
14073     SetForegroundWindow(hother);
14074     hactive = GetForegroundWindow();
14075     ok(hother == hactive, "Wrong foreground window (%p != %p)\n", hother, hactive);
14076 
14077     hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hchild, test_dlg_proc, 0);
14078     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
14079 
14080     SetForegroundWindow(hdlg);
14081     test_enddialog_seq(hdlg, hchild);
14082 
14083     hactive = GetForegroundWindow();
14084     ok(hactive == hchild, "Wrong foreground window (active: %p, parent: %p, dlg: %p, other: %p child: %p)\n", hactive, hparent, hdlg, hother, hchild);
14085 
14086     DestroyWindow(hdlg);
14087 
14088     /* Now set WS_CHILD style flag so that it's a real child and its parent will be dialog's owner. */
14089     SetWindowLongW(hchild, GWL_STYLE, GetWindowLongW(hchild, GWL_STYLE) | WS_CHILD);
14090 
14091     SetForegroundWindow(hother);
14092     hactive = GetForegroundWindow();
14093     ok(hother == hactive, "Wrong foreground window (%p != %p)\n", hother, hactive);
14094 
14095     hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hchild, test_dlg_proc, 0);
14096     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
14097 
14098     SetForegroundWindow(hdlg);
14099     test_enddialog_seq2(hdlg, hparent);
14100 
14101     hactive = GetForegroundWindow();
14102     ok(hactive == hparent, "Wrong foreground window (active: %p, parent: %p, dlg: %p, other: %p child: %p)\n", hactive, hparent, hdlg, hother, hchild);
14103     DestroyWindow(hdlg);
14104     DestroyWindow(hchild);
14105     DestroyWindow(hparent);
14106     DestroyWindow(hother);
14107     flush_sequence();
14108 
14109     UnregisterClassA(cls.lpszClassName, cls.hInstance);
14110 }
14111 
14112 static void test_nullCallback(void)
14113 {
14114     HWND hwnd;
14115 
14116     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
14117                            100, 100, 200, 200, 0, 0, 0, NULL);
14118     ok (hwnd != 0, "Failed to create overlapped window\n");
14119 
14120     SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
14121     flush_events();
14122     DestroyWindow(hwnd);
14123 }
14124 
14125 /* SetActiveWindow( 0 ) hwnd visible */
14126 static const struct message SetActiveWindowSeq0[] =
14127 {
14128     { HCBT_ACTIVATE, hook|optional },
14129     { WM_NCACTIVATE, sent|wparam, 0 },
14130     { WM_GETTEXT, sent|defwinproc|optional },
14131     { WM_ACTIVATE, sent|wparam, 0 },
14132     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
14133     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
14134     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
14135     { WM_KILLFOCUS, sent|optional },
14136     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
14137     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
14138     { WM_NCACTIVATE, sent|wparam|optional, 1 },
14139     { WM_GETTEXT, sent|defwinproc|optional },
14140     { WM_ACTIVATE, sent|wparam|optional, 1 },
14141     { HCBT_SETFOCUS, hook|optional },
14142     { WM_KILLFOCUS, sent|defwinproc|optional },
14143     { WM_IME_SETCONTEXT, sent|defwinproc|optional },
14144     { WM_IME_SETCONTEXT, sent|defwinproc|optional },
14145     { WM_IME_SETCONTEXT, sent|optional },
14146     { WM_IME_SETCONTEXT, sent|optional },
14147     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
14148     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
14149     { WM_SETFOCUS, sent|defwinproc|optional },
14150     { WM_GETTEXT, sent|optional },
14151     { 0 }
14152 };
14153 /* SetActiveWindow( hwnd ) hwnd visible */
14154 static const struct message SetActiveWindowSeq1[] =
14155 {
14156     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
14157     { 0 }
14158 };
14159 /* SetActiveWindow( popup ) hwnd visible, popup visible */
14160 static const struct message SetActiveWindowSeq2[] =
14161 {
14162     { HCBT_ACTIVATE, hook },
14163     { WM_NCACTIVATE, sent|wparam, 0 },
14164     { WM_GETTEXT, sent|defwinproc|optional },
14165     { WM_ACTIVATE, sent|wparam, 0 },
14166     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
14167     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
14168     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
14169     { WM_NCPAINT, sent|optional },
14170     { WM_GETTEXT, sent|defwinproc|optional },
14171     { WM_ERASEBKGND, sent|optional },
14172     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14173     { WM_NCACTIVATE, sent|wparam, 1 },
14174     { WM_GETTEXT, sent|defwinproc|optional },
14175     { WM_ACTIVATE, sent|wparam, 1 },
14176     { HCBT_SETFOCUS, hook },
14177     { WM_KILLFOCUS, sent|defwinproc },
14178     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
14179     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
14180     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
14181     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
14182     { WM_SETFOCUS, sent|defwinproc },
14183     { WM_GETTEXT, sent|optional },
14184     { 0 }
14185 };
14186 
14187 /* SetActiveWindow( hwnd ) hwnd not visible */
14188 static const struct message SetActiveWindowSeq3[] =
14189 {
14190     { HCBT_ACTIVATE, hook },
14191     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
14192     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
14193     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
14194     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14195     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14196     { WM_ACTIVATEAPP, sent|wparam, 1 },
14197     { WM_ACTIVATEAPP, sent|wparam, 1 },
14198     { WM_NCACTIVATE, sent|wparam, 1 },
14199     { WM_ACTIVATE, sent|wparam, 1 },
14200     { HCBT_SETFOCUS, hook },
14201     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
14202     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
14203     { WM_SETFOCUS, sent|defwinproc },
14204     { 0 }
14205 };
14206 /* SetActiveWindow( popup ) hwnd not visible, popup not visible */
14207 static const struct message SetActiveWindowSeq4[] =
14208 {
14209     { HCBT_ACTIVATE, hook },
14210     { WM_NCACTIVATE, sent|wparam, 0 },
14211     { WM_GETTEXT, sent|defwinproc|optional },
14212     { WM_ACTIVATE, sent|wparam, 0 },
14213     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
14214     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
14215     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
14216     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14217     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14218     { WM_NCACTIVATE, sent|wparam, 1 },
14219     { WM_GETTEXT, sent|defwinproc|optional },
14220     { WM_ACTIVATE, sent|wparam, 1 },
14221     { HCBT_SETFOCUS, hook },
14222     { WM_KILLFOCUS, sent|defwinproc },
14223     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
14224     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
14225     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
14226     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
14227     { WM_SETFOCUS, sent|defwinproc },
14228     { 0 }
14229 };
14230 
14231 
14232 static void test_SetActiveWindow(void)
14233 {
14234     HWND hwnd, popup, ret;
14235 
14236     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
14237                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
14238                            100, 100, 200, 200, 0, 0, 0, NULL);
14239 
14240     popup = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
14241                            WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_POPUP,
14242                            100, 100, 200, 200, hwnd, 0, 0, NULL);
14243 
14244     ok(hwnd != 0, "Failed to create overlapped window\n");
14245     ok(popup != 0, "Failed to create popup window\n");
14246     SetForegroundWindow( popup );
14247     flush_sequence();
14248 
14249     trace("SetActiveWindow(0)\n");
14250     ret = SetActiveWindow(0);
14251     ok( ret == popup, "Failed to SetActiveWindow(0)\n");
14252     ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", FALSE);
14253     flush_sequence();
14254 
14255     trace("SetActiveWindow(hwnd), hwnd visible\n");
14256     ret = SetActiveWindow(hwnd);
14257     if (ret == hwnd) ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE);
14258     flush_sequence();
14259 
14260     trace("SetActiveWindow(popup), hwnd visible, popup visible\n");
14261     ret = SetActiveWindow(popup);
14262     ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n");
14263     ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visible", FALSE);
14264     flush_sequence();
14265 
14266     ShowWindow(hwnd, SW_HIDE);
14267     ShowWindow(popup, SW_HIDE);
14268     flush_sequence();
14269 
14270     trace("SetActiveWindow(hwnd), hwnd not visible\n");
14271     ret = SetActiveWindow(hwnd);
14272     ok( ret == NULL, "SetActiveWindow(hwnd), hwnd not visible, previous is %p\n", ret );
14273     ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE);
14274     flush_sequence();
14275 
14276     trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n");
14277     ret = SetActiveWindow(popup);
14278     ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n");
14279     ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visible", TRUE);
14280     flush_sequence();
14281 
14282     trace("done\n");
14283 
14284     DestroyWindow(hwnd);
14285 }
14286 
14287 static const struct message SetForegroundWindowSeq[] =
14288 {
14289     { WM_NCACTIVATE, sent|wparam, 0 },
14290     { WM_GETTEXT, sent|defwinproc|optional },
14291     { WM_ACTIVATE, sent|wparam, 0 },
14292     { WM_ACTIVATEAPP, sent|wparam, 0 },
14293     { WM_KILLFOCUS, sent },
14294     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
14295     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
14296     { 0 }
14297 };
14298 
14299 static void test_SetForegroundWindow(void)
14300 {
14301     HWND hwnd;
14302 
14303     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
14304                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
14305                            100, 100, 200, 200, 0, 0, 0, NULL);
14306     ok (hwnd != 0, "Failed to create overlapped window\n");
14307     SetForegroundWindow( hwnd );
14308     flush_sequence();
14309 
14310     trace("SetForegroundWindow( 0 )\n");
14311     SetForegroundWindow( 0 );
14312     ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
14313     trace("SetForegroundWindow( GetDesktopWindow() )\n");
14314     SetForegroundWindow( GetDesktopWindow() );
14315     ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
14316                                         "foreground top level window", FALSE);
14317     trace("done\n");
14318 
14319     DestroyWindow(hwnd);
14320 }
14321 
14322 static DWORD get_input_codepage( void )
14323 {
14324     DWORD cp;
14325     int ret;
14326     HKL hkl = GetKeyboardLayout( 0 );
14327 
14328     ret = GetLocaleInfoW( LOWORD(hkl), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
14329                           (WCHAR *)&cp, sizeof(cp) / sizeof(WCHAR) );
14330     if (!ret) cp = CP_ACP;
14331     return cp;
14332 }
14333 
14334 static void test_dbcs_wm_char(void)
14335 {
14336     BYTE dbch[2];
14337     WCHAR wch, bad_wch;
14338     HWND hwnd, hwnd2;
14339     MSG msg;
14340     DWORD time;
14341     POINT pt;
14342     DWORD_PTR res;
14343     CPINFOEXA cpinfo;
14344     UINT i, j, k;
14345     struct message wmCharSeq[2];
14346     BOOL ret;
14347     DWORD cp = get_input_codepage();
14348 
14349     if (!pGetCPInfoExA)
14350     {
14351         win_skip("GetCPInfoExA is not available\n");
14352         return;
14353     }
14354 
14355     pGetCPInfoExA( cp, 0, &cpinfo );
14356     if (cpinfo.MaxCharSize != 2)
14357     {
14358         skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
14359         return;
14360     }
14361 
14362     dbch[0] = dbch[1] = 0;
14363     wch = 0;
14364     bad_wch = cpinfo.UnicodeDefaultChar;
14365     for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
14366         for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
14367             for (k = 128; k <= 255; k++)
14368             {
14369                 char str[2];
14370                 WCHAR wstr[2];
14371                 str[0] = j;
14372                 str[1] = k;
14373                 if (MultiByteToWideChar( cp, 0, str, 2, wstr, 2 ) == 1 &&
14374                     WideCharToMultiByte( cp, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
14375                     (BYTE)str[0] == j && (BYTE)str[1] == k &&
14376                     HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
14377                 {
14378                     dbch[0] = j;
14379                     dbch[1] = k;
14380                     wch = wstr[0];
14381                     break;
14382                 }
14383             }
14384 
14385     if (!wch)
14386     {
14387         skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
14388         return;
14389     }
14390     trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
14391            dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
14392 
14393     hwnd = CreateWindowExW(0, testWindowClassW, NULL,
14394                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
14395     hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
14396                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
14397     ok (hwnd != 0, "Failed to create overlapped window\n");
14398     ok (hwnd2 != 0, "Failed to create overlapped window\n");
14399     flush_sequence();
14400 
14401     memset( wmCharSeq, 0, sizeof(wmCharSeq) );
14402     wmCharSeq[0].message = WM_CHAR;
14403     wmCharSeq[0].flags = sent|wparam;
14404     wmCharSeq[0].wParam = wch;
14405 
14406     /* posted message */
14407     PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14408     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14409     ok( !ret, "got message %x\n", msg.message );
14410     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14411     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14412     ok( ret, "no message\n" );
14413     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14414     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
14415     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14416     ok( !ret, "got message %x\n", msg.message );
14417 
14418     /* posted thread message */
14419     PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
14420     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14421     ok( !ret, "got message %x\n", msg.message );
14422     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14423     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14424     ok( ret, "no message\n" );
14425     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14426     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
14427     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14428     ok( !ret, "got message %x\n", msg.message );
14429 
14430     /* sent message */
14431     flush_sequence();
14432     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14433     ok_sequence( WmEmptySeq, "no messages", FALSE );
14434     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14435     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14436     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14437     ok( !ret, "got message %x\n", msg.message );
14438 
14439     /* sent message with timeout */
14440     flush_sequence();
14441     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
14442     ok_sequence( WmEmptySeq, "no messages", FALSE );
14443     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
14444     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14445     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14446     ok( !ret, "got message %x\n", msg.message );
14447 
14448     /* sent message with timeout and callback */
14449     flush_sequence();
14450     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
14451     ok_sequence( WmEmptySeq, "no messages", FALSE );
14452     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
14453     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14454     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14455     ok( !ret, "got message %x\n", msg.message );
14456 
14457     /* sent message with callback */
14458     flush_sequence();
14459     SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14460     ok_sequence( WmEmptySeq, "no messages", FALSE );
14461     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
14462     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14463     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14464     ok( !ret, "got message %x\n", msg.message );
14465 
14466     /* direct window proc call */
14467     flush_sequence();
14468     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
14469     ok_sequence( WmEmptySeq, "no messages", FALSE );
14470     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
14471     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14472 
14473     /* dispatch message */
14474     msg.hwnd = hwnd;
14475     msg.message = WM_CHAR;
14476     msg.wParam = dbch[0];
14477     msg.lParam = 0;
14478     DispatchMessageA( &msg );
14479     ok_sequence( WmEmptySeq, "no messages", FALSE );
14480     msg.wParam = dbch[1];
14481     DispatchMessageA( &msg );
14482     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14483 
14484     /* window handle is irrelevant */
14485     flush_sequence();
14486     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
14487     ok_sequence( WmEmptySeq, "no messages", FALSE );
14488     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14489     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14490     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14491     ok( !ret, "got message %x\n", msg.message );
14492 
14493     /* interleaved post and send */
14494     flush_sequence();
14495     PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
14496     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
14497     ok_sequence( WmEmptySeq, "no messages", FALSE );
14498     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14499     ok( !ret, "got message %x\n", msg.message );
14500     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14501     ok_sequence( WmEmptySeq, "no messages", FALSE );
14502     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14503     ok( ret, "no message\n" );
14504     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14505     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
14506     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14507     ok( !ret, "got message %x\n", msg.message );
14508     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14509     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14510     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14511     ok( !ret, "got message %x\n", msg.message );
14512 
14513     /* interleaved sent message and winproc */
14514     flush_sequence();
14515     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14516     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
14517     ok_sequence( WmEmptySeq, "no messages", FALSE );
14518     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14519     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14520     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
14521     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14522 
14523     /* interleaved winproc and dispatch */
14524     msg.hwnd = hwnd;
14525     msg.message = WM_CHAR;
14526     msg.wParam = dbch[0];
14527     msg.lParam = 0;
14528     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
14529     DispatchMessageA( &msg );
14530     ok_sequence( WmEmptySeq, "no messages", FALSE );
14531     msg.wParam = dbch[1];
14532     DispatchMessageA( &msg );
14533     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14534     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
14535     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14536 
14537     /* interleaved sends */
14538     flush_sequence();
14539     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14540     SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
14541     ok_sequence( WmEmptySeq, "no messages", FALSE );
14542     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
14543     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14544     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14545     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14546 
14547     /* dbcs WM_CHAR */
14548     flush_sequence();
14549     SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
14550     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14551     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14552     ok( !ret, "got message %x\n", msg.message );
14553 
14554     /* other char messages are not magic */
14555     PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
14556     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14557     ok( ret, "no message\n" );
14558     ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
14559     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
14560     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14561     ok( !ret, "got message %x\n", msg.message );
14562     PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
14563     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14564     ok( ret, "no message\n" );
14565     ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
14566     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
14567     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14568     ok( !ret, "got message %x\n", msg.message );
14569 
14570     /* test retrieving messages */
14571 
14572     PostMessageW( hwnd, WM_CHAR, wch, 0 );
14573     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14574     ok( ret, "no message\n" );
14575     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14576     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14577     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14578     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14579     ok( ret, "no message\n" );
14580     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14581     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14582     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14583     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14584     ok( !ret, "got message %x\n", msg.message );
14585 
14586     /* message filters */
14587     PostMessageW( hwnd, WM_CHAR, wch, 0 );
14588     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14589     ok( ret, "no message\n" );
14590     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14591     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14592     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14593     /* message id is filtered, hwnd is not */
14594     ret = PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE );
14595     ok( !ret, "no message\n" );
14596     ret = PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE );
14597     ok( ret, "no message\n" );
14598     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14599     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14600     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14601     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14602     ok( !ret, "got message %x\n", msg.message );
14603 
14604     /* mixing GetMessage and PostMessage */
14605     PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
14606     ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
14607     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14608     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14609     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14610     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
14611     time = msg.time;
14612     pt = msg.pt;
14613     ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time );
14614     ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
14615     ok( ret, "no message\n" );
14616     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14617     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14618     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14619     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
14620     ok( msg.time == time, "bad time %x/%x\n", msg.time, time );
14621     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 );
14622     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14623     ok( !ret, "got message %x\n", msg.message );
14624 
14625     /* without PM_REMOVE */
14626     PostMessageW( hwnd, WM_CHAR, wch, 0 );
14627     ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
14628     ok( ret, "no message\n" );
14629     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14630     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14631     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14632     ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
14633     ok( ret, "no message\n" );
14634     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14635     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14636     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14637     ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
14638     ok( ret, "no message\n" );
14639     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14640     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14641     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14642     ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
14643     ok( ret, "no message\n" );
14644     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14645     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14646     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14647     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14648     ok( !ret, "got message %x\n", msg.message );
14649 
14650     DestroyWindow(hwnd);
14651     DestroyWindow(hwnd2);
14652 }
14653 
14654 static void test_unicode_wm_char(void)
14655 {
14656     HWND hwnd;
14657     MSG msg;
14658     struct message seq[2];
14659     HKL hkl_orig, hkl_greek;
14660     DWORD cp;
14661     LCID thread_locale;
14662 
14663     hkl_orig = GetKeyboardLayout( 0 );
14664     GetLocaleInfoW( LOWORD( hkl_orig ), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, (WCHAR*)&cp, sizeof(cp) / sizeof(WCHAR) );
14665     if (cp != 1252)
14666     {
14667         skip( "Default codepage %d\n", cp );
14668         return;
14669     }
14670 
14671     hkl_greek = LoadKeyboardLayoutA( "00000408", 0 );
14672     if (!hkl_greek || hkl_greek == hkl_orig /* win2k */)
14673     {
14674         skip( "Unable to load Greek keyboard layout\n" );
14675         return;
14676     }
14677 
14678     hwnd = CreateWindowExW( 0, testWindowClassW, NULL, WS_OVERLAPPEDWINDOW,
14679                             100, 100, 200, 200, 0, 0, 0, NULL );
14680     flush_sequence();
14681 
14682     PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
14683 
14684     while (GetMessageW( &msg, hwnd, 0, 0 ))
14685     {
14686         if (!ignore_message( msg.message )) break;
14687     }
14688 
14689     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14690     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14691     ok( msg.wParam == 0x3b1, "bad wparam %lx\n", msg.wParam );
14692     ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
14693 
14694     DispatchMessageW( &msg );
14695 
14696     memset( seq, 0, sizeof(seq) );
14697     seq[0].message = WM_CHAR;
14698     seq[0].flags = sent|wparam;
14699     seq[0].wParam = 0x3b1;
14700 
14701     ok_sequence( seq, "unicode WM_CHAR", FALSE );
14702 
14703     flush_sequence();
14704 
14705     /* greek alpha -> 'a' in cp1252 */
14706     PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
14707 
14708     ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
14709     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14710     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14711     ok( msg.wParam == 0x61, "bad wparam %lx\n", msg.wParam );
14712     ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
14713 
14714     DispatchMessageA( &msg );
14715 
14716     seq[0].wParam = 0x61;
14717     ok_sequence( seq, "unicode WM_CHAR", FALSE );
14718 
14719     thread_locale = GetThreadLocale();
14720     ActivateKeyboardLayout( hkl_greek, 0 );
14721     ok( GetThreadLocale() == thread_locale, "locale changed from %08x to %08x\n",
14722         thread_locale, GetThreadLocale() );
14723 
14724     flush_sequence();
14725 
14726     /* greek alpha -> 0xe1 in cp1253 */
14727     PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
14728 
14729     ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
14730     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14731     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14732     ok( msg.wParam == 0xe1, "bad wparam %lx\n", msg.wParam );
14733     ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
14734 
14735     DispatchMessageA( &msg );
14736 
14737     seq[0].wParam = 0x3b1;
14738     ok_sequence( seq, "unicode WM_CHAR", FALSE );
14739 
14740     DestroyWindow( hwnd );
14741     ActivateKeyboardLayout( hkl_orig, 0 );
14742     UnloadKeyboardLayout( hkl_greek );
14743 }
14744 
14745 #define ID_LISTBOX 0x000f
14746 
14747 static const struct message wm_lb_setcursel_0[] =
14748 {
14749     { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
14750     { WM_CTLCOLORLISTBOX, sent|parent },
14751     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
14752     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
14753     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
14754     { 0 }
14755 };
14756 static const struct message wm_lb_setcursel_1[] =
14757 {
14758     { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
14759     { WM_CTLCOLORLISTBOX, sent|parent },
14760     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
14761     { WM_CTLCOLORLISTBOX, sent|parent },
14762     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
14763     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
14764     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
14765     { 0 }
14766 };
14767 static const struct message wm_lb_setcursel_2[] =
14768 {
14769     { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
14770     { WM_CTLCOLORLISTBOX, sent|parent },
14771     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
14772     { WM_CTLCOLORLISTBOX, sent|parent },
14773     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
14774     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
14775     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
14776     { 0 }
14777 };
14778 static const struct message wm_lb_click_0[] =
14779 {
14780     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
14781     { HCBT_SETFOCUS, hook },
14782     { WM_KILLFOCUS, sent|parent },
14783     { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
14784     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
14785     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
14786     { WM_SETFOCUS, sent|defwinproc },
14787 
14788     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
14789     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
14790     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
14791     { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
14792     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
14793 
14794     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
14795     { WM_CTLCOLORLISTBOX, sent|parent },
14796     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
14797     { WM_CTLCOLORLISTBOX, sent|parent },
14798     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
14799     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
14800 
14801     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
14802     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
14803 
14804     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
14805     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
14806     { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
14807     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
14808     { 0 }
14809 };
14810 static const struct message wm_lb_deletestring[] =
14811 {
14812     { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
14813     { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
14814     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
14815     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
14816     { 0 }
14817 };
14818 static const struct message wm_lb_deletestring_reset[] =
14819 {
14820     { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
14821     { LB_RESETCONTENT, sent|wparam|lparam|defwinproc|optional, 0, 0 },
14822     { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
14823     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
14824     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
14825     { 0 }
14826 };
14827 static const struct message wm_lb_addstring[] =
14828 {
14829     { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef },
14830     { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed },
14831     { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee },
14832     { 0 }
14833 };
14834 static const struct message wm_lb_addstring_ownerdraw[] =
14835 {
14836     { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed },
14837     { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf0f2, 0xf30604ed },
14838     { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee },
14839     { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf1f2, 0xf30604ee },
14840     { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef },
14841     { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf2f2, 0xf30604ef },
14842     { 0 }
14843 };
14844 static const struct message wm_lb_addstring_sort_ownerdraw[] =
14845 {
14846     { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed },
14847     { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf0f2, 0xf30604ed },
14848     { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee },
14849     { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ed, 0xf30604ee },
14850     { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf1f2, 0xf30604ee },
14851     { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef },
14852     { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ed, 0xf30604ef },
14853     { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ee, 0xf30604ef },
14854     { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf2f2, 0xf30604ef },
14855     { 0 }
14856 };
14857 
14858 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
14859 
14860 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
14861 
14862 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
14863 {
14864     static LONG defwndproc_counter = 0;
14865     LRESULT ret;
14866     struct recvd_message msg;
14867 
14868     /* do not log painting messages */
14869     if (message != WM_PAINT &&
14870         message != WM_NCPAINT &&
14871         message != WM_SYNCPAINT &&
14872         message != WM_ERASEBKGND &&
14873         message != WM_NCHITTEST &&
14874         message != WM_GETTEXT &&
14875         !ignore_message( message ))
14876     {
14877         msg.hwnd = hwnd;
14878         msg.message = message;
14879         msg.flags = sent|wparam|lparam;
14880         if (defwndproc_counter) msg.flags |= defwinproc;
14881         msg.wParam = wp;
14882         if (message == LB_ADDSTRING)
14883             msg.lParam = lp ? hash_Ly((const char *)lp) : 0;
14884         else
14885             msg.lParam = lp;
14886         msg.descr = "listbox";
14887         add_message(&msg);
14888     }
14889 
14890     defwndproc_counter++;
14891     ret = CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
14892     defwndproc_counter--;
14893 
14894     return ret;
14895 }
14896 
14897 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
14898                                int caret_index, int top_index, int line)
14899 {
14900     LRESULT ret;
14901 
14902     /* calling an orig proc helps to avoid unnecessary message logging */
14903     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
14904     ok_(__FILE__, line)(ret == count, "expected count %d, got %ld\n", count, ret);
14905     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
14906     ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret);
14907     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
14908     ok_(__FILE__, line)(ret == caret_index ||
14909                         broken(cur_sel == -1 && caret_index == 0 && ret == -1),  /* nt4 */
14910                         "expected caret index %d, got %ld\n", caret_index, ret);
14911     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
14912     ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret);
14913 }
14914 
14915 static void test_listbox_messages(void)
14916 {
14917     HWND parent, listbox;
14918     LRESULT ret;
14919 
14920     parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW  | WS_VISIBLE,
14921                              100, 100, 200, 200, 0, 0, 0, NULL);
14922     /* with LBS_HASSTRINGS */
14923     listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
14924                               WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
14925                               10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
14926     listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
14927 
14928     check_lb_state(listbox, 0, LB_ERR, 0, 0);
14929 
14930     flush_sequence();
14931 
14932     log_all_parent_messages++;
14933 
14934     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
14935     ok(ret == 0, "expected 0, got %ld\n", ret);
14936     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
14937     ok(ret == 1, "expected 1, got %ld\n", ret);
14938     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
14939     ok(ret == 2, "expected 2, got %ld\n", ret);
14940 
14941     ok_sequence(wm_lb_addstring_ownerdraw, "LB_ADDSTRING", FALSE);
14942     check_lb_state(listbox, 3, LB_ERR, 0, 0);
14943 
14944     flush_sequence();
14945 
14946     trace("selecting item 0\n");
14947     ret = SendMessageA(listbox, LB_SETCURSEL, 0, 0);
14948     ok(ret == 0, "expected 0, got %ld\n", ret);
14949     ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
14950     check_lb_state(listbox, 3, 0, 0, 0);
14951     flush_sequence();
14952 
14953     trace("selecting item 1\n");
14954     ret = SendMessageA(listbox, LB_SETCURSEL, 1, 0);
14955     ok(ret == 1, "expected 1, got %ld\n", ret);
14956     ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
14957     check_lb_state(listbox, 3, 1, 1, 0);
14958 
14959     trace("selecting item 2\n");
14960     ret = SendMessageA(listbox, LB_SETCURSEL, 2, 0);
14961     ok(ret == 2, "expected 2, got %ld\n", ret);
14962     ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
14963     check_lb_state(listbox, 3, 2, 2, 0);
14964 
14965     trace("clicking on item 0\n");
14966     ret = SendMessageA(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
14967     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
14968     ret = SendMessageA(listbox, WM_LBUTTONUP, 0, 0);
14969     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
14970     ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
14971     check_lb_state(listbox, 3, 0, 0, 0);
14972     flush_sequence();
14973 
14974     trace("deleting item 0\n");
14975     ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14976     ok(ret == 2, "expected 2, got %ld\n", ret);
14977     ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
14978     check_lb_state(listbox, 2, -1, 0, 0);
14979     flush_sequence();
14980 
14981     trace("deleting item 0\n");
14982     ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14983     ok(ret == 1, "expected 1, got %ld\n", ret);
14984     ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
14985     check_lb_state(listbox, 1, -1, 0, 0);
14986     flush_sequence();
14987 
14988     trace("deleting item 0\n");
14989     ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14990     ok(ret == 0, "expected 0, got %ld\n", ret);
14991     ok_sequence(wm_lb_deletestring_reset, "LB_DELETESTRING 0", FALSE );
14992     check_lb_state(listbox, 0, -1, 0, 0);
14993     flush_sequence();
14994 
14995     trace("deleting item 0\n");
14996     ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14997     ok(ret == LB_ERR, "expected LB_ERR, got %ld\n", ret);
14998     check_lb_state(listbox, 0, -1, 0, 0);
14999     flush_sequence();
15000 
15001     log_all_parent_messages--;
15002 
15003     DestroyWindow(listbox);
15004 
15005     /* with LBS_SORT and without LBS_HASSTRINGS */
15006     listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
15007                               WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_SORT | WS_VISIBLE,
15008                               10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
15009     listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
15010 
15011     check_lb_state(listbox, 0, LB_ERR, 0, 0);
15012 
15013     flush_sequence();
15014 
15015     log_all_parent_messages++;
15016 
15017     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
15018     ok(ret == 0, "expected 0, got %ld\n", ret);
15019     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
15020     ok(ret == 1, "expected 1, got %ld\n", ret);
15021     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
15022     ok(ret == 2, "expected 2, got %ld\n", ret);
15023 
15024     ok_sequence(wm_lb_addstring_sort_ownerdraw, "LB_ADDSTRING", FALSE);
15025     check_lb_state(listbox, 3, LB_ERR, 0, 0);
15026 
15027     log_all_parent_messages--;
15028 
15029     DestroyWindow(listbox);
15030 
15031     /* with LBS_HASSTRINGS */
15032     listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
15033                               WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | WS_VISIBLE,
15034                               10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
15035     listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
15036 
15037     check_lb_state(listbox, 0, LB_ERR, 0, 0);
15038 
15039     flush_sequence();
15040 
15041     log_all_parent_messages++;
15042 
15043     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
15044     ok(ret == 0, "expected 0, got %ld\n", ret);
15045     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
15046     ok(ret == 1, "expected 1, got %ld\n", ret);
15047     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
15048     ok(ret == 2, "expected 2, got %ld\n", ret);
15049 
15050     ok_sequence(wm_lb_addstring, "LB_ADDSTRING", FALSE);
15051     check_lb_state(listbox, 3, LB_ERR, 0, 0);
15052 
15053     log_all_parent_messages--;
15054 
15055     DestroyWindow(listbox);
15056 
15057     /* with LBS_HASSTRINGS and LBS_SORT */
15058     listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
15059                               WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | LBS_SORT | WS_VISIBLE,
15060                               10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
15061     listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
15062 
15063     check_lb_state(listbox, 0, LB_ERR, 0, 0);
15064 
15065     flush_sequence();
15066 
15067     log_all_parent_messages++;
15068 
15069     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
15070     ok(ret == 0, "expected 0, got %ld\n", ret);
15071     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
15072     ok(ret == 0, "expected 0, got %ld\n", ret);
15073     ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
15074     ok(ret == 1, "expected 1, got %ld\n", ret);
15075 
15076     ok_sequence(wm_lb_addstring, "LB_ADDSTRING", FALSE);
15077     check_lb_state(listbox, 3, LB_ERR, 0, 0);
15078 
15079     log_all_parent_messages--;
15080 
15081     DestroyWindow(listbox);
15082     DestroyWindow(parent);
15083 }
15084 
15085 /*************************** Menu test ******************************/
15086 static const struct message wm_popup_menu_1[] =
15087 {
15088     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
15089     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
15090     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0x20000001 },
15091     { WM_SYSKEYDOWN, sent|wparam|lparam, 'E', 0x20000001 },
15092     { WM_SYSCHAR, sent|wparam|lparam, 'e', 0x20000001 },
15093     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'e' },
15094     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
15095     { WM_INITMENU, sent|lparam, 0, 0 },
15096     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) },
15097     { WM_INITMENUPOPUP, sent|lparam, 0, 1 },
15098     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */
15099     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) },
15100     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 },
15101     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
15102     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001, 0, 0x40000000 },
15103     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */
15104     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
15105     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
15106     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
15107     { WM_MENUCOMMAND, sent }, /* |wparam, 200 - Win9x */
15108     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
15109     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
15110     { 0 }
15111 };
15112 static const struct message wm_popup_menu_2[] =
15113 {
15114     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
15115     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
15116     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
15117     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
15118     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
15119     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
15120     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
15121     { WM_INITMENU, sent|lparam, 0, 0 },
15122     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
15123     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
15124     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
15125     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
15126     { HCBT_CREATEWND, hook },
15127     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
15128                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
15129     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
15130     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
15131     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
15132     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
15133     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
15134     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
15135     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
15136     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
15137     { HCBT_DESTROYWND, hook },
15138     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
15139     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
15140     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
15141     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
15142     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
15143     { WM_MENUCOMMAND, sent }, /* |wparam, 100 - Win9x */
15144     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
15145     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
15146     { 0 }
15147 };
15148 static const struct message wm_popup_menu_3[] =
15149 {
15150     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
15151     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
15152     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
15153     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
15154     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
15155     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
15156     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
15157     { WM_INITMENU, sent|lparam, 0, 0 },
15158     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
15159     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
15160     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
15161     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
15162     { HCBT_CREATEWND, hook },
15163     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
15164                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
15165     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
15166     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
15167     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
15168     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
15169     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
15170     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
15171     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
15172     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
15173     { HCBT_DESTROYWND, hook },
15174     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
15175     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
15176     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
15177     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
15178     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
15179     { WM_COMMAND, sent|wparam|lparam, 100, 0 },
15180     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
15181     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
15182     { 0 }
15183 };
15184 
15185 static const struct message wm_single_menu_item[] =
15186 {
15187     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
15188     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
15189     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0x20000001 },
15190     { WM_SYSKEYDOWN, sent|wparam|lparam, 'Q', 0x20000001 },
15191     { WM_SYSCHAR, sent|wparam|lparam, 'q', 0x20000001 },
15192     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'q' },
15193     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
15194     { WM_INITMENU, sent|lparam, 0, 0 },
15195     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(300,MF_HILITE) },
15196     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
15197     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
15198     { WM_MENUCOMMAND, sent },
15199     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0xe0000001 },
15200     { WM_SYSKEYUP, sent|wparam|lparam, 'Q', 0xe0000001 },
15201     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 },
15202     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
15203 
15204     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 1 },
15205     { WM_KEYDOWN, sent|wparam|lparam, VK_ESCAPE, 1 },
15206     { WM_CHAR,  sent|wparam|lparam, VK_ESCAPE, 0x00000001 },
15207     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 },
15208     { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
15209     { 0 }
15210 };
15211 
15212 static LRESULT WINAPI parent_menu_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
15213 {
15214     if (message == WM_ENTERIDLE ||
15215         message == WM_INITMENU ||
15216         message == WM_INITMENUPOPUP ||
15217         message == WM_MENUSELECT ||
15218         message == WM_PARENTNOTIFY ||
15219         message == WM_ENTERMENULOOP ||
15220         message == WM_EXITMENULOOP ||
15221         message == WM_UNINITMENUPOPUP ||
15222         message == WM_KEYDOWN ||
15223         message == WM_KEYUP ||
15224         message == WM_CHAR ||
15225         message == WM_SYSKEYDOWN ||
15226         message == WM_SYSKEYUP ||
15227         message == WM_SYSCHAR ||
15228         message == WM_COMMAND ||
15229         message == WM_MENUCOMMAND)
15230     {
15231         struct recvd_message msg;
15232 
15233         msg.hwnd = hwnd;
15234         msg.message = message;
15235         msg.flags = sent|wparam|lparam;
15236         msg.wParam = wp;
15237         msg.lParam = lp;
15238         msg.descr = "parent_menu_proc";
15239         add_message(&msg);
15240     }
15241 
15242     return DefWindowProcA(hwnd, message, wp, lp);
15243 }
15244 
15245 static void set_menu_style(HMENU hmenu, DWORD style)
15246 {
15247     MENUINFO mi;
15248     BOOL ret;
15249 
15250     mi.cbSize = sizeof(mi);
15251     mi.fMask = MIM_STYLE;
15252     mi.dwStyle = style;
15253     SetLastError(0xdeadbeef);
15254     ret = pSetMenuInfo(hmenu, &mi);
15255     ok(ret, "SetMenuInfo error %u\n", GetLastError());
15256 }
15257 
15258 static DWORD get_menu_style(HMENU hmenu)
15259 {
15260     MENUINFO mi;
15261     BOOL ret;
15262 
15263     mi.cbSize = sizeof(mi);
15264     mi.fMask = MIM_STYLE;
15265     mi.dwStyle = 0;
15266     SetLastError(0xdeadbeef);
15267     ret = pGetMenuInfo(hmenu, &mi);
15268     ok(ret, "GetMenuInfo error %u\n", GetLastError());
15269 
15270     return mi.dwStyle;
15271 }
15272 
15273 static void test_menu_messages(void)
15274 {
15275     MSG msg;
15276     WNDCLASSA cls;
15277     HMENU hmenu, hmenu_popup;
15278     HWND hwnd;
15279     DWORD style;
15280 
15281     if (!pGetMenuInfo || !pSetMenuInfo)
15282     {
15283         win_skip("GetMenuInfo and/or SetMenuInfo are not available\n");
15284         return;
15285     }
15286     cls.style = 0;
15287     cls.lpfnWndProc = parent_menu_proc;
15288     cls.cbClsExtra = 0;
15289     cls.cbWndExtra = 0;
15290     cls.hInstance = GetModuleHandleA(0);
15291     cls.hIcon = 0;
15292     cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
15293     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
15294     cls.lpszMenuName = NULL;
15295     cls.lpszClassName = "TestMenuClass";
15296     UnregisterClassA(cls.lpszClassName, cls.hInstance);
15297     if (!RegisterClassA(&cls)) assert(0);
15298 
15299     SetLastError(0xdeadbeef);
15300     hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
15301                            100, 100, 200, 200, 0, 0, 0, NULL);
15302     ok(hwnd != 0, "LoadMenuA error %u\n", GetLastError());
15303 
15304     SetLastError(0xdeadbeef);
15305     hmenu = LoadMenuA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
15306     ok(hmenu != 0, "LoadMenuA error %u\n", GetLastError());
15307 
15308     SetMenu(hwnd, hmenu);
15309     SetForegroundWindow( hwnd );
15310     flush_events();
15311 
15312     set_menu_style(hmenu, MNS_NOTIFYBYPOS);
15313     style = get_menu_style(hmenu);
15314     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
15315 
15316     hmenu_popup = GetSubMenu(hmenu, 0);
15317     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
15318     style = get_menu_style(hmenu_popup);
15319     ok(style == 0, "expected 0, got %u\n", style);
15320 
15321     hmenu_popup = GetSubMenu(hmenu_popup, 0);
15322     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
15323     style = get_menu_style(hmenu_popup);
15324     ok(style == 0, "expected 0, got %u\n", style);
15325 
15326     /* Alt+E, Enter */
15327     trace("testing a popup menu command\n");
15328     flush_sequence();
15329     keybd_event(VK_MENU, 0, 0, 0);
15330     keybd_event('E', 0, 0, 0);
15331     keybd_event('E', 0, KEYEVENTF_KEYUP, 0);
15332     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
15333     keybd_event(VK_RETURN, 0, 0, 0);
15334     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
15335     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15336     {
15337         TranslateMessage(&msg);
15338         DispatchMessageA(&msg);
15339     }
15340     if (!sequence_cnt)  /* we didn't get any message */
15341     {
15342         skip( "queuing key events not supported\n" );
15343         goto done;
15344     }
15345     /* win98 queues only a WM_KEYUP and doesn't start menu tracking */
15346     if (sequence[0].message == WM_KEYUP && sequence[0].wParam == VK_MENU)
15347     {
15348         win_skip( "menu tracking through VK_MENU not supported\n" );
15349         goto done;
15350     }
15351     ok_sequence(wm_popup_menu_1, "popup menu command", FALSE);
15352 
15353     /* Alt+F, Right, Enter */
15354     trace("testing submenu of a popup menu command\n");
15355     flush_sequence();
15356     keybd_event(VK_MENU, 0, 0, 0);
15357     keybd_event('F', 0, 0, 0);
15358     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
15359     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
15360     keybd_event(VK_RIGHT, 0, 0, 0);
15361     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
15362     keybd_event(VK_RETURN, 0, 0, 0);
15363     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
15364     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15365     {
15366         TranslateMessage(&msg);
15367         DispatchMessageA(&msg);
15368     }
15369     ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE);
15370 
15371     trace("testing single menu item command\n");
15372     flush_sequence();
15373     keybd_event(VK_MENU, 0, 0, 0);
15374     keybd_event('Q', 0, 0, 0);
15375     keybd_event('Q', 0, KEYEVENTF_KEYUP, 0);
15376     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
15377     keybd_event(VK_ESCAPE, 0, 0, 0);
15378     keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
15379     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15380     {
15381         TranslateMessage(&msg);
15382         DispatchMessageA(&msg);
15383     }
15384     ok_sequence(wm_single_menu_item, "single menu item command", FALSE);
15385 
15386     set_menu_style(hmenu, 0);
15387     style = get_menu_style(hmenu);
15388     ok(style == 0, "expected 0, got %u\n", style);
15389 
15390     hmenu_popup = GetSubMenu(hmenu, 0);
15391     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
15392     set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS);
15393     style = get_menu_style(hmenu_popup);
15394     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
15395 
15396     hmenu_popup = GetSubMenu(hmenu_popup, 0);
15397     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
15398     style = get_menu_style(hmenu_popup);
15399     ok(style == 0, "expected 0, got %u\n", style);
15400 
15401     /* Alt+F, Right, Enter */
15402     trace("testing submenu of a popup menu command\n");
15403     flush_sequence();
15404     keybd_event(VK_MENU, 0, 0, 0);
15405     keybd_event('F', 0, 0, 0);
15406     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
15407     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
15408     keybd_event(VK_RIGHT, 0, 0, 0);
15409     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
15410     keybd_event(VK_RETURN, 0, 0, 0);
15411     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
15412     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15413     {
15414         TranslateMessage(&msg);
15415         DispatchMessageA(&msg);
15416     }
15417     ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE);
15418 
15419 done:
15420     DestroyWindow(hwnd);
15421     DestroyMenu(hmenu);
15422 }
15423 
15424 
15425 static void test_paintingloop(void)
15426 {
15427     HWND hwnd;
15428 
15429     paint_loop_done = FALSE;
15430     hwnd = CreateWindowExA(0x0,"PaintLoopWindowClass",
15431                                "PaintLoopWindowClass",WS_OVERLAPPEDWINDOW,
15432                                 100, 100, 100, 100, 0, 0, 0, NULL );
15433     ok(hwnd != 0, "PaintLoop window error %u\n", GetLastError());
15434     ShowWindow(hwnd,SW_NORMAL);
15435     SetFocus(hwnd);
15436 
15437     while (!paint_loop_done)
15438     {
15439         MSG msg;
15440         if (PeekMessageA(&msg, 0, 0, 0, 1))
15441         {
15442             TranslateMessage(&msg);
15443             DispatchMessageA(&msg);
15444         }
15445     }
15446     DestroyWindow(hwnd);
15447 }
15448 
15449 static const struct message NCRBUTTONDOWNSeq[] =
15450 {
15451     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
15452     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
15453     { WM_CAPTURECHANGED, sent },
15454     { WM_CONTEXTMENU, sent, /*hwnd*/0, -1 },
15455     { 0 }
15456 };
15457 
15458 static const struct message NCXBUTTONUPSeq1[] =
15459 {
15460     { WM_APPCOMMAND, sent|lparam, /*hwnd*/0, MAKELPARAM(0, FAPPCOMMAND_MOUSE | APPCOMMAND_BROWSER_BACKWARD) },
15461     { 0 }
15462 };
15463 
15464 static const struct message NCXBUTTONUPSeq2[] =
15465 {
15466     { WM_APPCOMMAND, sent|lparam, /*hwnd*/0, MAKELPARAM(0, FAPPCOMMAND_MOUSE | APPCOMMAND_BROWSER_FORWARD) },
15467     { 0 }
15468 };
15469 
15470 /* DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0) to minimized visible window */
15471 static const struct message WmRestoreMinimizedOverlappedSeq[] =
15472 {
15473     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_RESTORE, 0 },
15474     { HCBT_MINMAX, hook },
15475     { WM_QUERYOPEN, sent },
15476     { WM_GETTEXT, sent|optional },
15477     { WM_NCACTIVATE, sent|optional },
15478     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
15479     { WM_WINDOWPOSCHANGED, sent|optional },
15480     { WM_WINDOWPOSCHANGING, sent|optional },
15481     { WM_GETMINMAXINFO, sent|defwinproc },
15482     { WM_NCCALCSIZE, sent|optional },
15483     { WM_NCPAINT, sent|optional },
15484     { WM_GETTEXT, sent|defwinproc|optional },
15485     { WM_ERASEBKGND, sent|optional },
15486     { WM_WINDOWPOSCHANGED, sent|optional },
15487     { HCBT_ACTIVATE, hook },
15488     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
15489     { WM_ACTIVATEAPP, sent|wparam, TRUE },
15490     { WM_NCACTIVATE, sent|wparam, TRUE },
15491     { WM_GETTEXT, sent|defwinproc|optional },
15492     { WM_ACTIVATE, sent|wparam, TRUE },
15493     { HCBT_SETFOCUS, hook },
15494     { WM_SETFOCUS, sent|defwinproc },
15495     { WM_NCPAINT, sent },
15496     { WM_GETTEXT, sent|defwinproc|optional },
15497     { WM_ERASEBKGND, sent },
15498     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_FRAMECHANGED|SWP_STATECHANGED },
15499     { WM_MOVE, sent|defwinproc },
15500     { WM_SIZE, sent|defwinproc },
15501     { WM_NCCALCSIZE, sent|optional },
15502     { WM_NCPAINT, sent|optional },
15503     { WM_ERASEBKGND, sent|optional },
15504     { WM_ACTIVATE, sent|wparam, TRUE },
15505     { WM_SYNCPAINT, sent|optional },
15506     { WM_PAINT, sent },
15507     { 0 }
15508 };
15509 
15510 static struct message WmContextMenuSeq[] = {
15511     { WM_CONTEXTMENU, sent|wparam, 0 }, /* wparams set in the code */
15512     { WM_CONTEXTMENU, sent|wparam|defwinproc, 0 },
15513     { WM_CONTEXTMENU, sent|wparam|defwinproc, 0 },
15514     { 0 }
15515 };
15516 
15517 struct rbuttonup_thread_data
15518 {
15519     HWND hwnd;
15520     HANDLE wndproc_finished;
15521 };
15522 
15523 static DWORD CALLBACK post_rbuttonup_msg( void *arg )
15524 {
15525     struct rbuttonup_thread_data *data = arg;
15526     DWORD ret;
15527 
15528     ret = WaitForSingleObject( data->wndproc_finished, 500 );
15529     todo_wine ok( ret == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", ret );
15530     if( ret == WAIT_OBJECT_0 ) return 0;
15531 
15532     PostMessageA( data->hwnd, WM_RBUTTONUP, 0, 0 );
15533     return 0;
15534 }
15535 
15536 static void test_defwinproc(void)
15537 {
15538     HWND hwnd, child[3];
15539     MSG msg;
15540     BOOL gotwmquit = FALSE;
15541     POINT pos;
15542     RECT rect;
15543     INT x, y;
15544     LRESULT res;
15545     struct rbuttonup_thread_data data;
15546     char buffA[64];
15547     HANDLE thread;
15548 
15549     hwnd = CreateWindowExA(0, "TestWindowClass", "test_defwndproc",
15550             WS_VISIBLE | WS_CAPTION | WS_OVERLAPPEDWINDOW, 0,0,500,100,0,0,0, NULL);
15551     assert(hwnd);
15552     flush_events();
15553 
15554     buffA[0] = 0;
15555     GetWindowTextA(hwnd, buffA, ARRAY_SIZE(buffA));
15556     ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
15557 
15558     /* Zero high word of the lParam */
15559     res = DefWindowProcA(hwnd, WM_SETTEXT, 0, 0x1234);
15560     ok(res == 0, "WM_SETTEXT was expected to fail, %ld\n", res);
15561 
15562     GetWindowTextA(hwnd, buffA, ARRAY_SIZE(buffA));
15563     ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
15564 
15565     res = DefWindowProcW(hwnd, WM_SETTEXT, 0, 0x1234);
15566     ok(res == 0, "WM_SETTEXT was expected to fail, %ld\n", res);
15567 
15568     GetWindowTextA(hwnd, buffA, ARRAY_SIZE(buffA));
15569     ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
15570 
15571     ShowWindow(hwnd, SW_MINIMIZE);
15572     flush_events();
15573     flush_sequence();
15574 
15575     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
15576     flush_events();
15577     ok_sequence(WmRestoreMinimizedOverlappedSeq, "DefWindowProcA(SC_RESTORE):overlapped", TRUE);
15578     flush_sequence();
15579 
15580     child[0] = CreateWindowExA(0, "TestWindowClass", "1st child",
15581                                WS_VISIBLE | WS_CHILD, 0,0,500,100, hwnd, 0, 0, NULL);
15582     child[1] = CreateWindowExA(0, "TestWindowClass", "2nd child",
15583                                WS_VISIBLE | WS_CHILD, 0,0,500,100, child[0], 0, 0, NULL);
15584     child[2] = CreateWindowExA(0, "TestWindowClass", "3rd child",
15585                                WS_VISIBLE | WS_CHILD, 0,0,500,100, child[1], 0, 0, NULL);
15586     flush_events();
15587     flush_sequence();
15588     test_context_menu = TRUE;
15589     DefWindowProcA(child[2], WM_CONTEXTMENU, 0xcafe, 0);
15590     test_context_menu = FALSE;
15591     WmContextMenuSeq[0].wParam = (WPARAM)child[2];
15592     WmContextMenuSeq[1].wParam = (WPARAM)child[1];
15593     WmContextMenuSeq[2].wParam = (WPARAM)child[0];
15594     ok_sequence(WmContextMenuSeq, "DefWindowProcA(WM_CONTEXTMENU)", FALSE);
15595     DestroyWindow(child[0]);
15596 
15597     GetCursorPos(&pos);
15598     GetWindowRect(hwnd, &rect);
15599     x = (rect.left+rect.right) / 2;
15600     y = rect.top + GetSystemMetrics(SM_CYFRAME) + 1;
15601     SetCursorPos(x, y);
15602     flush_events();
15603     res = DefWindowProcA( hwnd, WM_NCHITTEST, 0, MAKELPARAM(x, y));
15604     ok(res == HTCAPTION, "WM_NCHITTEST returned %ld\n", res);
15605 
15606     mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 );
15607     mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 );
15608     flush_events();
15609 
15610     flush_sequence();
15611     mouse_event( MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0 );
15612     /* workaround for missing support for clicking on window frame */
15613     data.hwnd = hwnd;
15614     data.wndproc_finished = CreateEventA( NULL, FALSE, FALSE, NULL );
15615     thread = CreateThread( NULL, 0, post_rbuttonup_msg, (void*)&data, 0, NULL );
15616 
15617     DefWindowProcA( hwnd, WM_NCRBUTTONDOWN, HTCAPTION, MAKELPARAM(x, y));
15618     ok_sequence(NCRBUTTONDOWNSeq, "WM_NCRBUTTONDOWN on caption", FALSE);
15619 
15620     res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, 0, MAKELPARAM(x, y));
15621     ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15622     ok_sequence(WmEmptySeq, "WM_NCXBUTTONUP without button", FALSE);
15623 
15624     res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, XBUTTON1), MAKELPARAM(x, y));
15625     ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15626     ok_sequence(NCXBUTTONUPSeq1, "WM_NCXBUTTONUP with XBUTTON1", FALSE);
15627 
15628     res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, XBUTTON2), MAKELPARAM(x, y));
15629     ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15630     ok_sequence(NCXBUTTONUPSeq2, "WM_NCXBUTTONUP with XBUTTON2", FALSE);
15631 
15632     res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, 3), MAKELPARAM(x, y));
15633     ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15634     ok_sequence(WmEmptySeq, "WM_NCXBUTTONUP with invalid button", FALSE);
15635 
15636     SetEvent( data.wndproc_finished );
15637     WaitForSingleObject( thread, 1000 );
15638     CloseHandle( data.wndproc_finished );
15639     CloseHandle( thread );
15640 
15641     SetCursorPos(pos.x, pos.y);
15642 
15643     DefWindowProcA( hwnd, WM_ENDSESSION, 1, 0);
15644     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) {
15645         if( msg.message == WM_QUIT) gotwmquit = TRUE;
15646         DispatchMessageA( &msg );
15647     }
15648     ok(!gotwmquit, "Unexpected WM_QUIT message!\n");
15649     DestroyWindow( hwnd);
15650 }
15651 
15652 static void test_desktop_winproc(void)
15653 {
15654     HINSTANCE instance = GetModuleHandleA(NULL);
15655     RECT rect, default_rect;
15656     WNDPROC desktop_proc;
15657     char buffer[256];
15658     WNDCLASSA cls;
15659     LRESULT res;
15660     HWND hwnd;
15661     BOOL ret;
15662 
15663     ret = GetClassInfoA(instance, (const CHAR *)MAKEINTATOM(32769), &cls);
15664     ok(ret, "Failed to get desktop class.\n");
15665     desktop_proc = cls.lpfnWndProc;
15666 
15667     memset(&cls, 0, sizeof(cls));
15668     cls.lpfnWndProc = desktop_proc;
15669     cls.hInstance = instance;
15670     cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
15671     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
15672     cls.lpszClassName = "TestDesktopClass";
15673     ret = !!RegisterClassA(&cls);
15674     ok(ret, "Failed to register class.\n");
15675 
15676     hwnd = CreateWindowExA(0, cls.lpszClassName, "test_desktop_wndproc",
15677             WS_VISIBLE | WS_CAPTION | WS_OVERLAPPEDWINDOW, 0, 0, 500, 100, 0, 0, 0, NULL);
15678     if (!hwnd) /* win2003 */
15679     {
15680         skip("Failed to create window with desktop window procedure.\n");
15681         goto out_unregister;
15682     }
15683 
15684     memset(&cls, 0, sizeof(cls));
15685     ret = GetClassInfoA(instance, "TestDesktopClass", &cls);
15686     ok(ret, "Failed to get class info.\n");
15687     ok(cls.lpfnWndProc == desktop_proc, "Got %p, expected %p.\n", cls.lpfnWndProc, desktop_proc);
15688 
15689     GetWindowTextA(hwnd, buffer, ARRAY_SIZE(buffer));
15690     todo_wine ok(!strcmp(buffer, "test_desktop_wndproc"), "Got unexpected window text: %s.\n", buffer);
15691 
15692     res = CallWindowProcA(desktop_proc, hwnd, WM_SETTEXT, 0, (LPARAM)"test");
15693     ok(res == TRUE, "Failed to set text, %ld.\n", res);
15694     GetWindowTextA(hwnd, buffer, ARRAY_SIZE(buffer));
15695     ok(!strcmp(buffer, "test"), "Got unexpected window text: %s.\n", buffer);
15696 
15697     SetRect(&default_rect, 0, 0, 100, 100);
15698     res = DefWindowProcW(hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&default_rect);
15699     ok(!res, "Got unexpected result %ld.\n", res);
15700 
15701     SetRect(&rect, 0, 0, 100, 100);
15702     res = CallWindowProcA(desktop_proc, hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rect);
15703     ok(!res, "Got unexpected result %ld.\n", res);
15704     todo_wine ok(EqualRect(&rect, &default_rect), "rect Got %s, expected %s.\n",
15705             wine_dbgstr_rect(&rect), wine_dbgstr_rect(&default_rect));
15706 
15707     DestroyWindow(hwnd);
15708 
15709 out_unregister:
15710     UnregisterClassA("TestDesktopClass", instance);
15711 }
15712 
15713 #define clear_clipboard(hwnd)  clear_clipboard_(__LINE__, (hwnd))
15714 static void clear_clipboard_(int line, HWND hWnd)
15715 {
15716     BOOL succ;
15717     succ = OpenClipboard(hWnd);
15718     ok_(__FILE__, line)(succ, "OpenClipboard failed, err=%u\n", GetLastError());
15719     succ = EmptyClipboard();
15720     ok_(__FILE__, line)(succ, "EmptyClipboard failed, err=%u\n", GetLastError());
15721     succ = CloseClipboard();
15722     ok_(__FILE__, line)(succ, "CloseClipboard failed, err=%u\n", GetLastError());
15723 }
15724 
15725 #define expect_HWND(expected, got) expect_HWND_(__LINE__, (expected), (got))
15726 static void expect_HWND_(int line, HWND expected, HWND got)
15727 {
15728     ok_(__FILE__, line)(got==expected, "Expected %p, got %p\n", expected, got);
15729 }
15730 
15731 static WNDPROC pOldViewerProc;
15732 
15733 static LRESULT CALLBACK recursive_viewer_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
15734 {
15735     static BOOL recursion_guard;
15736 
15737     if (message == WM_DRAWCLIPBOARD && !recursion_guard)
15738     {
15739         recursion_guard = TRUE;
15740         clear_clipboard(hWnd);
15741         recursion_guard = FALSE;
15742     }
15743     return CallWindowProcA(pOldViewerProc, hWnd, message, wParam, lParam);
15744 }
15745 
15746 static void test_clipboard_viewers(void)
15747 {
15748     static struct message wm_change_cb_chain[] =
15749     {
15750         { WM_CHANGECBCHAIN, sent|wparam|lparam, 0, 0 },
15751         { 0 }
15752     };
15753     static const struct message wm_clipboard_destroyed[] =
15754     {
15755         { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
15756         { 0 }
15757     };
15758     static struct message wm_clipboard_changed[] =
15759     {
15760         { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
15761         { 0 }
15762     };
15763     static struct message wm_clipboard_changed_and_owned[] =
15764     {
15765         { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
15766         { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
15767         { 0 }
15768     };
15769 
15770     HINSTANCE hInst = GetModuleHandleA(NULL);
15771     HWND hWnd1, hWnd2, hWnd3;
15772     HWND hOrigViewer;
15773     HWND hRet;
15774 
15775     hWnd1 = CreateWindowExA(0, "TestWindowClass", "Clipboard viewer test wnd 1",
15776         WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
15777         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
15778         GetDesktopWindow(), NULL, hInst, NULL);
15779     hWnd2 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 2",
15780         WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
15781         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
15782         GetDesktopWindow(), NULL, hInst, NULL);
15783     hWnd3 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 3",
15784         WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
15785         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
15786         GetDesktopWindow(), NULL, hInst, NULL);
15787     trace("clipbd viewers: hWnd1=%p, hWnd2=%p, hWnd3=%p\n", hWnd1, hWnd2, hWnd3);
15788     assert(hWnd1 && hWnd2 && hWnd3);
15789 
15790     CountClipboardFormats(); /* Ensure that we do not have an X11 update to the clipboard */
15791     flush_sequence();
15792 
15793     /* Test getting the clipboard viewer and setting the viewer to NULL. */
15794     hOrigViewer = GetClipboardViewer();
15795     hRet = SetClipboardViewer(NULL);
15796     ok_sequence(WmEmptySeq, "set viewer to NULL", FALSE);
15797     expect_HWND(hOrigViewer, hRet);
15798     expect_HWND(NULL, GetClipboardViewer());
15799 
15800     /* Test registering hWnd1 as a viewer. */
15801     hRet = SetClipboardViewer(hWnd1);
15802     wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
15803     ok_sequence(wm_clipboard_changed, "set viewer NULL->1", FALSE);
15804     expect_HWND(NULL, hRet);
15805     expect_HWND(hWnd1, GetClipboardViewer());
15806 
15807     /* Test that changing the clipboard actually refreshes the registered viewer. */
15808     clear_clipboard(hWnd1);
15809     wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
15810     ok_sequence(wm_clipboard_changed, "clear clipbd (viewer=owner=1)", FALSE);
15811 
15812     /* Again, but with different owner. */
15813     clear_clipboard(hWnd2);
15814     wm_clipboard_changed_and_owned[1].wParam = (WPARAM) GetClipboardOwner();
15815     ok_sequence(wm_clipboard_changed_and_owned, "clear clipbd (viewer=1, owner=2)", FALSE);
15816 
15817     /* Test re-registering same window. */
15818     hRet = SetClipboardViewer(hWnd1);
15819     wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
15820     ok_sequence(wm_clipboard_changed, "set viewer 1->1", FALSE);
15821     expect_HWND(hWnd1, hRet);
15822     expect_HWND(hWnd1, GetClipboardViewer());
15823 
15824     /* Test ChangeClipboardChain. */
15825     ChangeClipboardChain(hWnd2, hWnd3);
15826     wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
15827     wm_change_cb_chain[0].lParam = (LPARAM) hWnd3;
15828     ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=3)", FALSE);
15829     expect_HWND(hWnd1, GetClipboardViewer());
15830 
15831     ChangeClipboardChain(hWnd2, NULL);
15832     wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
15833     wm_change_cb_chain[0].lParam = 0;
15834     ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=NULL)", FALSE);
15835     expect_HWND(hWnd1, GetClipboardViewer());
15836 
15837     ChangeClipboardChain(NULL, hWnd2);
15838     ok_sequence(WmEmptySeq, "change chain (viewer=1, remove=NULL, next=2)", FALSE);
15839     expect_HWND(hWnd1, GetClipboardViewer());
15840 
15841     /* Actually change clipboard viewer with ChangeClipboardChain. */
15842     ChangeClipboardChain(hWnd1, hWnd2);
15843     ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=2)", FALSE);
15844     expect_HWND(hWnd2, GetClipboardViewer());
15845 
15846     /* Test that no refresh messages are sent when viewer has unregistered. */
15847     clear_clipboard(hWnd2);
15848     ok_sequence(WmEmptySeq, "clear clipd (viewer=2, owner=1)", FALSE);
15849 
15850     /* Register hWnd1 again. */
15851     ChangeClipboardChain(hWnd2, hWnd1);
15852     ok_sequence(WmEmptySeq, "change chain (viewer=remove=2, next=1)", FALSE);
15853     expect_HWND(hWnd1, GetClipboardViewer());
15854 
15855     /* Subclass hWnd1 so that when it receives a WM_DRAWCLIPBOARD message, it
15856      * changes the clipboard. When this happens, the system shouldn't send
15857      * another WM_DRAWCLIPBOARD (as this could cause an infinite loop).
15858      */
15859     pOldViewerProc = (WNDPROC) SetWindowLongPtrA(hWnd1, GWLP_WNDPROC, (LONG_PTR) recursive_viewer_proc);
15860     clear_clipboard(hWnd2);
15861     /* The clipboard owner is changed in recursive_viewer_proc: */
15862     wm_clipboard_changed[0].wParam = (WPARAM) hWnd2;
15863     ok_sequence(wm_clipboard_changed, "recursive clear clipbd (viewer=1, owner=2)", TRUE);
15864 
15865     /* Test unregistering. */
15866     ChangeClipboardChain(hWnd1, NULL);
15867     ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=NULL)", FALSE);
15868     expect_HWND(NULL, GetClipboardViewer());
15869 
15870     clear_clipboard(hWnd1);
15871     ok_sequence(wm_clipboard_destroyed, "clear clipbd (no viewer, owner=1)", FALSE);
15872 
15873     DestroyWindow(hWnd1);
15874     DestroyWindow(hWnd2);
15875     DestroyWindow(hWnd3);
15876     SetClipboardViewer(hOrigViewer);
15877 }
15878 
15879 static void test_PostMessage(void)
15880 {
15881     static const struct
15882     {
15883         HWND hwnd;
15884         BOOL ret;
15885     } data[] =
15886     {
15887         { HWND_TOP /* 0 */, TRUE },
15888         { HWND_BROADCAST, TRUE },
15889         { HWND_BOTTOM, TRUE },
15890         { HWND_TOPMOST, TRUE },
15891         { HWND_NOTOPMOST, FALSE },
15892         { HWND_MESSAGE, FALSE },
15893         { (HWND)0xdeadbeef, FALSE }
15894     };
15895     int i;
15896     HWND hwnd;
15897     BOOL ret;
15898     MSG msg;
15899     static const WCHAR staticW[] = {'s','t','a','t','i','c',0};
15900 
15901     SetLastError(0xdeadbeef);
15902     hwnd = CreateWindowExW(0, staticW, NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
15903     if (!hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
15904     {
15905         win_skip("Skipping some PostMessage tests on Win9x/WinMe\n");
15906         return;
15907     }
15908     assert(hwnd);
15909 
15910     flush_events();
15911 
15912     PostMessageA(hwnd, WM_USER+1, 0x1234, 0x5678);
15913     PostMessageA(0, WM_USER+2, 0x5678, 0x1234);
15914 
15915     for (i = 0; i < ARRAY_SIZE(data); i++)
15916     {
15917         memset(&msg, 0xab, sizeof(msg));
15918         ret = PeekMessageA(&msg, data[i].hwnd, 0, 0, PM_NOREMOVE);
15919         ok(ret == data[i].ret, "%d: hwnd %p expected %d, got %d\n", i, data[i].hwnd, data[i].ret, ret);
15920         if (data[i].ret)
15921         {
15922             if (data[i].hwnd)
15923                 ok(ret && msg.hwnd == 0 && msg.message == WM_USER+2 &&
15924                    msg.wParam == 0x5678 && msg.lParam == 0x1234,
15925                    "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/0/WM_USER+2/0x5678/0x1234\n",
15926                    i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam);
15927             else
15928                 ok(ret && msg.hwnd == hwnd && msg.message == WM_USER+1 &&
15929                    msg.wParam == 0x1234 && msg.lParam == 0x5678,
15930                    "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/%p/WM_USER+1/0x1234/0x5678\n",
15931                    i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam, msg.hwnd);
15932         }
15933     }
15934 
15935     DestroyWindow(hwnd);
15936     flush_events();
15937 }
15938 
15939 static LPARAM g_broadcast_lparam;
15940 static LRESULT WINAPI broadcast_test_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
15941 {
15942     WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
15943 
15944     if (wParam == 0xbaadbeef)
15945         g_broadcast_lparam = wParam;
15946     else
15947         g_broadcast_lparam = 0;
15948 
15949     return CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
15950 }
15951 
15952 static void test_broadcast(void)
15953 {
15954     static const UINT messages[] =
15955     {
15956         WM_USER-1,
15957         WM_USER,
15958         WM_USER+1,
15959         0xc000-1,
15960         0xc000, /* lowest possible atom returned by RegisterWindowMessage */
15961         0xffff,
15962     };
15963     WNDPROC oldproc;
15964     unsigned int i;
15965     HWND hwnd;
15966 
15967     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, NULL);
15968     ok(hwnd != NULL, "got %p\n", hwnd);
15969 
15970     oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)broadcast_test_proc);
15971     SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
15972 
15973     for (i = 0; i < ARRAY_SIZE(messages); i++)
15974     {
15975         BOOL ret;
15976         MSG msg;
15977 
15978         flush_events();
15979         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15980             ;
15981 
15982         /* post, broadcast */
15983         ret = PostMessageA(HWND_BROADCAST, messages[i], 0, 0);
15984         ok(ret, "%d: got %d, error %d\n", i, ret, GetLastError());
15985 
15986         memset(&msg, 0xab, sizeof(msg));
15987         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
15988         if (messages[i] < WM_USER || messages[i] >= 0xc000)
15989         {
15990             ok(ret, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError());
15991             ok(msg.hwnd == hwnd, "%d: got %p\n", i, msg.hwnd);
15992         }
15993         else
15994         {
15995             ok(!ret, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError());
15996         }
15997 
15998         /* post, topmost */
15999         ret = PostMessageA(HWND_TOPMOST, messages[i], 0, 0);
16000         ok(ret, "%d: got %d, error %d\n", i, ret, GetLastError());
16001 
16002         memset(&msg, 0xab, sizeof(msg));
16003         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
16004         if (messages[i] < WM_USER || messages[i] >= 0xc000)
16005         {
16006             ok(ret, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError());
16007             ok(msg.hwnd == hwnd, "%d: got %p\n", i, msg.hwnd);
16008         }
16009         else
16010         {
16011             ok(!ret, "%d: got %d, error %d\n", i, ret, GetLastError());
16012         }
16013 
16014         /* send, broadcast */
16015         g_broadcast_lparam = 0xdead;
16016         ret = SendMessageTimeoutA(HWND_BROADCAST, messages[i], 0xbaadbeef, 0, SMTO_NORMAL, 2000, NULL);
16017         if (!ret && GetLastError() == ERROR_TIMEOUT)
16018             win_skip("broadcasting test %d, timeout\n", i);
16019         else
16020         {
16021             if (messages[i] < WM_USER || messages[i] >= 0xc000)
16022             {
16023                 ok(g_broadcast_lparam == 0xbaadbeef, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
16024                     g_broadcast_lparam, GetLastError());
16025             }
16026             else
16027             {
16028                 ok(g_broadcast_lparam == 0xdead, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
16029                     g_broadcast_lparam, GetLastError());
16030             }
16031         }
16032 
16033         /* send, topmost */
16034         g_broadcast_lparam = 0xdead;
16035         ret = SendMessageTimeoutA(HWND_TOPMOST, messages[i], 0xbaadbeef, 0, SMTO_NORMAL, 2000, NULL);
16036         if (!ret && GetLastError() == ERROR_TIMEOUT)
16037             win_skip("broadcasting test %d, timeout\n", i);
16038         else
16039         {
16040             if (messages[i] < WM_USER || messages[i] >= 0xc000)
16041             {
16042                 ok(g_broadcast_lparam == 0xbaadbeef, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
16043                     g_broadcast_lparam, GetLastError());
16044             }
16045             else
16046             {
16047                 ok(g_broadcast_lparam == 0xdead, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
16048                     g_broadcast_lparam, GetLastError());
16049             }
16050         }
16051     }
16052 
16053     DestroyWindow(hwnd);
16054 }
16055 
16056 static const struct
16057 {
16058     DWORD exp, broken;
16059     BOOL todo;
16060 } wait_idle_expect[] =
16061 {
16062 /* 0 */  { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
16063          { WAIT_TIMEOUT, 0,            FALSE },
16064          { WAIT_TIMEOUT, 0,            FALSE },
16065          { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
16066          { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
16067 /* 5 */  { WAIT_TIMEOUT, 0,            FALSE },
16068          { WAIT_TIMEOUT, 0,            FALSE },
16069          { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
16070          { 0,            0,            FALSE },
16071          { 0,            0,            FALSE },
16072 /* 10 */ { 0,            0,            FALSE },
16073          { 0,            0,            FALSE },
16074          { 0,            WAIT_TIMEOUT, FALSE },
16075          { 0,            0,            FALSE },
16076          { 0,            0,            FALSE },
16077 /* 15 */ { 0,            0,            FALSE },
16078          { WAIT_TIMEOUT, 0,            FALSE },
16079          { WAIT_TIMEOUT, 0,            FALSE },
16080          { WAIT_TIMEOUT, 0,            FALSE },
16081          { WAIT_TIMEOUT, 0,            FALSE },
16082 /* 20 */ { WAIT_TIMEOUT, 0,            FALSE },
16083 };
16084 
16085 static DWORD CALLBACK do_wait_idle_child_thread( void *arg )
16086 {
16087     MSG msg;
16088 
16089     PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
16090     Sleep( 200 );
16091     MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
16092     return 0;
16093 }
16094 
16095 static void do_wait_idle_child( int arg )
16096 {
16097     WNDCLASSA cls;
16098     MSG msg;
16099     HWND hwnd = 0;
16100     HANDLE thread;
16101     DWORD id;
16102     HANDLE start_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_start" );
16103     HANDLE end_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_end" );
16104 
16105     memset( &cls, 0, sizeof(cls) );
16106     cls.lpfnWndProc   = DefWindowProcA;
16107     cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
16108     cls.hCursor       = LoadCursorA(0, (LPCSTR)IDC_ARROW);
16109     cls.lpszClassName = "TestClass";
16110     RegisterClassA( &cls );
16111 
16112     PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );  /* create the msg queue */
16113 
16114     ok( start_event != 0, "failed to create start event, error %u\n", GetLastError() );
16115     ok( end_event != 0, "failed to create end event, error %u\n", GetLastError() );
16116 
16117     switch (arg)
16118     {
16119     case 0:
16120         SetEvent( start_event );
16121         break;
16122     case 1:
16123         SetEvent( start_event );
16124         Sleep( 200 );
16125         PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
16126         break;
16127     case 2:
16128         SetEvent( start_event );
16129         Sleep( 200 );
16130         PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
16131         PostThreadMessageA( GetCurrentThreadId(), WM_COMMAND, 0x1234, 0xabcd );
16132         PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
16133         break;
16134     case 3:
16135         SetEvent( start_event );
16136         Sleep( 200 );
16137         SendMessageA( HWND_BROADCAST, WM_WININICHANGE, 0, 0 );
16138         break;
16139     case 4:
16140         SetEvent( start_event );
16141         Sleep( 200 );
16142         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
16143         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
16144         break;
16145     case 5:
16146         SetEvent( start_event );
16147         Sleep( 200 );
16148         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
16149         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
16150         break;
16151     case 6:
16152         SetEvent( start_event );
16153         Sleep( 200 );
16154         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
16155         while (PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ))
16156         {
16157             GetMessageA( &msg, 0, 0, 0 );
16158             DispatchMessageA( &msg );
16159         }
16160         break;
16161     case 7:
16162         SetEvent( start_event );
16163         Sleep( 200 );
16164         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
16165         SetTimer( hwnd, 3, 1, NULL );
16166         Sleep( 200 );
16167         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
16168         break;
16169     case 8:
16170         SetEvent( start_event );
16171         Sleep( 200 );
16172         PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
16173         MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
16174         break;
16175     case 9:
16176         SetEvent( start_event );
16177         Sleep( 200 );
16178         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
16179         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
16180         for (;;) GetMessageA( &msg, 0, 0, 0 );
16181         break;
16182     case 10:
16183         SetEvent( start_event );
16184         Sleep( 200 );
16185         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
16186         SetTimer( hwnd, 3, 1, NULL );
16187         Sleep( 200 );
16188         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
16189         break;
16190     case 11:
16191         SetEvent( start_event );
16192         Sleep( 200 );
16193         return;  /* exiting the process makes WaitForInputIdle return success too */
16194     case 12:
16195         PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
16196         Sleep( 200 );
16197         MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
16198         SetEvent( start_event );
16199         break;
16200     case 13:
16201         SetEvent( start_event );
16202         PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
16203         Sleep( 200 );
16204         thread = CreateThread( NULL, 0, do_wait_idle_child_thread, NULL, 0, &id );
16205         WaitForSingleObject( thread, 10000 );
16206         CloseHandle( thread );
16207         break;
16208     case 14:
16209         SetEvent( start_event );
16210         Sleep( 200 );
16211         PeekMessageA( &msg, HWND_TOPMOST, 0, 0, PM_NOREMOVE );
16212         break;
16213     case 15:
16214         SetEvent( start_event );
16215         Sleep( 200 );
16216         PeekMessageA( &msg, HWND_BROADCAST, 0, 0, PM_NOREMOVE );
16217         break;
16218     case 16:
16219         SetEvent( start_event );
16220         Sleep( 200 );
16221         PeekMessageA( &msg, HWND_BOTTOM, 0, 0, PM_NOREMOVE );
16222         break;
16223     case 17:
16224         SetEvent( start_event );
16225         Sleep( 200 );
16226         PeekMessageA( &msg, (HWND)0xdeadbeef, 0, 0, PM_NOREMOVE );
16227         break;
16228     case 18:
16229         SetEvent( start_event );
16230         Sleep( 200 );
16231         PeekMessageA( &msg, HWND_NOTOPMOST, 0, 0, PM_NOREMOVE );
16232         break;
16233     case 19:
16234         SetEvent( start_event );
16235         Sleep( 200 );
16236         PeekMessageA( &msg, HWND_MESSAGE, 0, 0, PM_NOREMOVE );
16237         break;
16238     case 20:
16239         SetEvent( start_event );
16240         Sleep( 200 );
16241         PeekMessageA( &msg, GetDesktopWindow(), 0, 0, PM_NOREMOVE );
16242         break;
16243     }
16244     WaitForSingleObject( end_event, 2000 );
16245     CloseHandle( start_event );
16246     CloseHandle( end_event );
16247     if (hwnd) DestroyWindow( hwnd );
16248 }
16249 
16250 static LRESULT CALLBACK wait_idle_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
16251 {
16252     if (msg == WM_WININICHANGE) Sleep( 200 );  /* make sure the child waits */
16253     return DefWindowProcA( hwnd, msg, wp, lp );
16254 }
16255 
16256 static DWORD CALLBACK wait_idle_thread( void *arg )
16257 {
16258     WNDCLASSA cls;
16259     MSG msg;
16260     HWND hwnd;
16261 
16262     memset( &cls, 0, sizeof(cls) );
16263     cls.lpfnWndProc   = wait_idle_proc;
16264     cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
16265     cls.hCursor       = LoadCursorA(0, (LPCSTR)IDC_ARROW);
16266     cls.lpszClassName = "TestClass";
16267     RegisterClassA( &cls );
16268 
16269     hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL);
16270     while (GetMessageA( &msg, 0, 0, 0 )) DispatchMessageA( &msg );
16271     DestroyWindow(hwnd);
16272     return 0;
16273 }
16274 
16275 static void test_WaitForInputIdle( char *argv0 )
16276 {
16277     char path[MAX_PATH];
16278     PROCESS_INFORMATION pi;
16279     STARTUPINFOA startup;
16280     BOOL ret;
16281     HANDLE start_event, end_event, thread;
16282     unsigned int i;
16283     DWORD id;
16284     const IMAGE_DOS_HEADER *dos = (const IMAGE_DOS_HEADER *)GetModuleHandleA(0);
16285     const IMAGE_NT_HEADERS *nt = (const IMAGE_NT_HEADERS *)((const char *)dos + dos->e_lfanew);
16286     BOOL console_app = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_GUI);
16287 
16288     if (console_app)  /* build the test with -mwindows for better coverage */
16289         trace( "not built as a GUI app, WaitForInputIdle may not be fully tested\n" );
16290 
16291     start_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_start");
16292     end_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_end");
16293     ok(start_event != 0, "failed to create start event, error %u\n", GetLastError());
16294     ok(end_event != 0, "failed to create end event, error %u\n", GetLastError());
16295 
16296     memset( &startup, 0, sizeof(startup) );
16297     startup.cb = sizeof(startup);
16298     startup.dwFlags = STARTF_USESHOWWINDOW;
16299     startup.wShowWindow = SW_SHOWNORMAL;
16300 
16301     thread = CreateThread( NULL, 0, wait_idle_thread, NULL, 0, &id );
16302 
16303     for (i = 0; i < ARRAY_SIZE(wait_idle_expect); i++)
16304     {
16305         ResetEvent( start_event );
16306         ResetEvent( end_event );
16307 #ifdef __REACTOS__
16308         sprintf( path, "%s msg_queue %u", argv0, i );
16309 #else
16310         sprintf( path, "%s msg %u", argv0, i );
16311 #endif
16312         ret = CreateProcessA( NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &pi );
16313         ok( ret, "CreateProcess '%s' failed err %u.\n", path, GetLastError() );
16314         if (ret)
16315         {
16316             ret = WaitForSingleObject( start_event, 5000 );
16317             ok( ret == WAIT_OBJECT_0, "%u: WaitForSingleObject failed\n", i );
16318             if (ret == WAIT_OBJECT_0)
16319             {
16320                 ret = WaitForInputIdle( pi.hProcess, 1000 );
16321                 if (ret == WAIT_FAILED)
16322                     ok( console_app ||
16323                         ret == wait_idle_expect[i].exp ||
16324                         broken(ret == wait_idle_expect[i].broken),
16325                         "%u: WaitForInputIdle error %08x expected %08x\n",
16326                         i, ret, wait_idle_expect[i].exp );
16327                 else todo_wine_if (wait_idle_expect[i].todo)
16328                     ok( ret == wait_idle_expect[i].exp || broken(ret == wait_idle_expect[i].broken),
16329                         "%u: WaitForInputIdle error %08x expected %08x\n",
16330                         i, ret, wait_idle_expect[i].exp );
16331                 SetEvent( end_event );
16332                 WaitForSingleObject( pi.hProcess, 1000 );  /* give it a chance to exit on its own */
16333             }
16334             TerminateProcess( pi.hProcess, 0 );  /* just in case */
16335             winetest_wait_child_process( pi.hProcess );
16336             ret = WaitForInputIdle( pi.hProcess, 100 );
16337             ok( ret == WAIT_FAILED, "%u: WaitForInputIdle after exit error %08x\n", i, ret );
16338             CloseHandle( pi.hProcess );
16339             CloseHandle( pi.hThread );
16340         }
16341     }
16342     CloseHandle( start_event );
16343     PostThreadMessageA( id, WM_QUIT, 0, 0 );
16344     WaitForSingleObject( thread, 10000 );
16345     CloseHandle( thread );
16346 }
16347 
16348 static const struct message WmSetParentSeq_1[] = {
16349     { WM_SHOWWINDOW, sent|wparam, 0 },
16350     { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
16351     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
16352     { WM_CHILDACTIVATE, sent },
16353     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE },
16354     { WM_MOVE, sent|defwinproc|wparam, 0 },
16355     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
16356     { WM_SHOWWINDOW, sent|wparam, 1 },
16357     { 0 }
16358 };
16359 
16360 static const struct message WmSetParentSeq_2[] = {
16361     { WM_SHOWWINDOW, sent|wparam, 0 },
16362     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
16363     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
16364     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
16365     { HCBT_SETFOCUS, hook|optional },
16366     { WM_NCACTIVATE, sent|wparam|optional, 0 },
16367     { WM_ACTIVATE, sent|wparam|optional, 0 },
16368     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
16369     { WM_KILLFOCUS, sent|wparam, 0 },
16370     { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
16371     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
16372     { HCBT_ACTIVATE, hook|optional },
16373     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
16374     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
16375     { WM_NCACTIVATE, sent|wparam|optional, 1 },
16376     { WM_ACTIVATE, sent|wparam|optional, 1 },
16377     { HCBT_SETFOCUS, hook|optional },
16378     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
16379     { WM_SETFOCUS, sent|optional|defwinproc },
16380     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOCLIENTSIZE },
16381     { WM_MOVE, sent|defwinproc|wparam, 0 },
16382     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
16383     { WM_SHOWWINDOW, sent|wparam, 1 },
16384     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
16385     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
16386     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
16387     { 0 }
16388 };
16389 
16390 
16391 static void test_SetParent(void)
16392 {
16393     HWND parent1, parent2, child, popup;
16394     RECT rc, rc_old;
16395 
16396     parent1 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
16397                             100, 100, 200, 200, 0, 0, 0, NULL);
16398     ok(parent1 != 0, "Failed to create parent1 window\n");
16399 
16400     parent2 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
16401                             400, 100, 200, 200, 0, 0, 0, NULL);
16402     ok(parent2 != 0, "Failed to create parent2 window\n");
16403 
16404     /* WS_CHILD window */
16405     child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD | WS_VISIBLE,
16406                            10, 10, 150, 150, parent1, 0, 0, NULL);
16407     ok(child != 0, "Failed to create child window\n");
16408 
16409     GetWindowRect(parent1, &rc);
16410     trace("parent1 %s\n", wine_dbgstr_rect(&rc));
16411     GetWindowRect(child, &rc_old);
16412     MapWindowPoints(0, parent1, (POINT *)&rc_old, 2);
16413     trace("child %s\n", wine_dbgstr_rect(&rc_old));
16414 
16415     flush_sequence();
16416 
16417     SetParent(child, parent2);
16418     flush_events();
16419     ok_sequence(WmSetParentSeq_1, "SetParent() visible WS_CHILD", FALSE);
16420 
16421     ok(GetWindowLongA(child, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
16422     ok(!IsWindowVisible(child), "IsWindowVisible() should return FALSE\n");
16423 
16424     GetWindowRect(parent2, &rc);
16425     trace("parent2 %s\n", wine_dbgstr_rect(&rc));
16426     GetWindowRect(child, &rc);
16427     MapWindowPoints(0, parent2, (POINT *)&rc, 2);
16428     trace("child %s\n", wine_dbgstr_rect(&rc));
16429 
16430     ok(EqualRect(&rc_old, &rc), "rects do not match %s / %s\n", wine_dbgstr_rect(&rc_old),
16431        wine_dbgstr_rect(&rc));
16432 
16433     /* WS_POPUP window */
16434     popup = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP | WS_VISIBLE,
16435                            20, 20, 100, 100, 0, 0, 0, NULL);
16436     ok(popup != 0, "Failed to create popup window\n");
16437 
16438     GetWindowRect(popup, &rc_old);
16439     trace("popup %s\n", wine_dbgstr_rect(&rc_old));
16440 
16441     flush_sequence();
16442 
16443     SetParent(popup, child);
16444     flush_events();
16445     ok_sequence(WmSetParentSeq_2, "SetParent() visible WS_POPUP", TRUE);
16446 
16447     ok(GetWindowLongA(popup, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
16448     ok(!IsWindowVisible(popup), "IsWindowVisible() should return FALSE\n");
16449 
16450     GetWindowRect(child, &rc);
16451     trace("parent2 %s\n", wine_dbgstr_rect(&rc));
16452     GetWindowRect(popup, &rc);
16453     MapWindowPoints(0, child, (POINT *)&rc, 2);
16454     trace("popup %s\n", wine_dbgstr_rect(&rc));
16455 
16456     ok(EqualRect(&rc_old, &rc), "rects do not match %s / %s\n", wine_dbgstr_rect(&rc_old),
16457        wine_dbgstr_rect(&rc));
16458 
16459     DestroyWindow(popup);
16460     DestroyWindow(child);
16461     DestroyWindow(parent1);
16462     DestroyWindow(parent2);
16463 
16464     flush_sequence();
16465 }
16466 
16467 static const struct message WmKeyReleaseOnly[] = {
16468     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x80000001 },
16469     { WM_KEYUP, sent|wparam|lparam, 0x41, 0x80000001 },
16470     { 0 }
16471 };
16472 static const struct message WmKeyPressNormal[] = {
16473     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x1 },
16474     { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x1 },
16475     { 0 }
16476 };
16477 static const struct message WmKeyPressRepeat[] = {
16478     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x40000001 },
16479     { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x40000001 },
16480     { 0 }
16481 };
16482 static const struct message WmKeyReleaseNormal[] = {
16483     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0xc0000001 },
16484     { WM_KEYUP, sent|wparam|lparam, 0x41, 0xc0000001 },
16485     { 0 }
16486 };
16487 
16488 static void test_keyflags(void)
16489 {
16490     HWND test_window;
16491     SHORT key_state;
16492     BYTE keyboard_state[256];
16493     MSG msg;
16494 
16495     test_window = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
16496                            100, 100, 200, 200, 0, 0, 0, NULL);
16497 
16498     flush_events();
16499     flush_sequence();
16500 
16501     /* keyup without a keydown */
16502     keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
16503     while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16504         DispatchMessageA(&msg);
16505     ok_sequence(WmKeyReleaseOnly, "key release only", TRUE);
16506 
16507     key_state = GetAsyncKeyState(0x41);
16508     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16509 
16510     key_state = GetKeyState(0x41);
16511     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16512 
16513     /* keydown */
16514     keybd_event(0x41, 0, 0, 0);
16515     while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16516         DispatchMessageA(&msg);
16517     ok_sequence(WmKeyPressNormal, "key press only", FALSE);
16518 
16519     key_state = GetAsyncKeyState(0x41);
16520     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16521 
16522     key_state = GetKeyState(0x41);
16523     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16524 
16525     /* keydown repeat */
16526     keybd_event(0x41, 0, 0, 0);
16527     while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16528         DispatchMessageA(&msg);
16529     ok_sequence(WmKeyPressRepeat, "key press repeat", FALSE);
16530 
16531     key_state = GetAsyncKeyState(0x41);
16532     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16533 
16534     key_state = GetKeyState(0x41);
16535     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16536 
16537     /* keyup */
16538     keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
16539     while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16540         DispatchMessageA(&msg);
16541     ok_sequence(WmKeyReleaseNormal, "key release repeat", FALSE);
16542 
16543     key_state = GetAsyncKeyState(0x41);
16544     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16545 
16546     key_state = GetKeyState(0x41);
16547     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16548 
16549     /* set the key state in this thread */
16550     GetKeyboardState(keyboard_state);
16551     keyboard_state[0x41] = 0x80;
16552     SetKeyboardState(keyboard_state);
16553 
16554     key_state = GetAsyncKeyState(0x41);
16555     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16556 
16557     /* keydown */
16558     keybd_event(0x41, 0, 0, 0);
16559     while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16560         DispatchMessageA(&msg);
16561     ok_sequence(WmKeyPressRepeat, "key press after setkeyboardstate", TRUE);
16562 
16563     key_state = GetAsyncKeyState(0x41);
16564     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16565 
16566     key_state = GetKeyState(0x41);
16567     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16568 
16569     /* clear the key state in this thread */
16570     GetKeyboardState(keyboard_state);
16571     keyboard_state[0x41] = 0;
16572     SetKeyboardState(keyboard_state);
16573 
16574     key_state = GetAsyncKeyState(0x41);
16575     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16576 
16577     /* keyup */
16578     keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
16579     while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16580         DispatchMessageA(&msg);
16581     ok_sequence(WmKeyReleaseOnly, "key release after setkeyboardstate", TRUE);
16582 
16583     key_state = GetAsyncKeyState(0x41);
16584     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16585 
16586     key_state = GetKeyState(0x41);
16587     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16588 
16589     DestroyWindow(test_window);
16590     flush_sequence();
16591 }
16592 
16593 static const struct message WmHotkeyPressLWIN[] = {
16594     { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
16595     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
16596     { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
16597     { 0 }
16598 };
16599 static const struct message WmHotkeyPress[] = {
16600     { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16601     { WM_HOTKEY, sent|wparam, 5 },
16602     { 0 }
16603 };
16604 static const struct message WmHotkeyRelease[] = {
16605     { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16606     { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 0x80000001 },
16607     { WM_KEYUP, sent|lparam, 0, 0x80000001 },
16608     { 0 }
16609 };
16610 static const struct message WmHotkeyReleaseLWIN[] = {
16611     { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
16612     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
16613     { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
16614     { 0 }
16615 };
16616 static const struct message WmHotkeyCombined[] = {
16617     { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
16618     { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16619     { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16620     { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
16621     { WM_APP, sent, 0, 0 },
16622     { WM_HOTKEY, sent|wparam, 5 },
16623     { WM_APP+1, sent, 0, 0 },
16624     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
16625     { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
16626     { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
16627     { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
16628     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
16629     { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
16630     { 0 }
16631 };
16632 static const struct message WmHotkeyPrevious[] = {
16633     { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
16634     { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16635     { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16636     { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
16637     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
16638     { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
16639     { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 1 },
16640     { WM_KEYDOWN, sent|lparam, 0, 1 },
16641     { HCBT_KEYSKIPPED, hook|optional|lparam, 0, 0xc0000001 },
16642     { WM_KEYUP, sent|lparam, 0, 0xc0000001 },
16643     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
16644     { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
16645     { 0 }
16646 };
16647 static const struct message WmHotkeyNew[] = {
16648     { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16649     { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16650     { WM_HOTKEY, sent|wparam, 5 },
16651     { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
16652     { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
16653     { 0 }
16654 };
16655 
16656 static int hotkey_letter;
16657 
16658 static LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
16659 {
16660     struct recvd_message msg;
16661 
16662     if (nCode == HC_ACTION)
16663     {
16664         KBDLLHOOKSTRUCT *kdbhookstruct = (KBDLLHOOKSTRUCT*)lParam;
16665 
16666         msg.hwnd = 0;
16667         msg.message = wParam;
16668         msg.flags = kbd_hook|wparam|lparam;
16669         msg.wParam = kdbhookstruct->vkCode;
16670         msg.lParam = kdbhookstruct->flags;
16671         msg.descr = "KeyboardHookProc";
16672         add_message(&msg);
16673 
16674         if (wParam == WM_KEYUP || wParam == WM_KEYDOWN)
16675         {
16676             ok(kdbhookstruct->vkCode == VK_LWIN || kdbhookstruct->vkCode == hotkey_letter,
16677                "unexpected keycode %x\n", kdbhookstruct->vkCode);
16678        }
16679     }
16680 
16681     return CallNextHookEx(hKBD_hook, nCode, wParam, lParam);
16682 }
16683 
16684 static void test_hotkey(void)
16685 {
16686     HWND test_window, taskbar_window;
16687     BOOL ret;
16688     MSG msg;
16689     DWORD queue_status;
16690     SHORT key_state;
16691 
16692     SetLastError(0xdeadbeef);
16693     ret = UnregisterHotKey(NULL, 0);
16694     if (ret == TRUE)
16695     {
16696         skip("hotkeys not supported\n");
16697         return;
16698     }
16699 
16700     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16701     ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16702        "unexpected error %d\n", GetLastError());
16703 
16704     test_window = CreateWindowExA(0, "HotkeyWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
16705                            100, 100, 200, 200, 0, 0, 0, NULL);
16706 
16707     flush_sequence();
16708 
16709     SetLastError(0xdeadbeef);
16710     ret = UnregisterHotKey(test_window, 0);
16711     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16712     ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16713        "unexpected error %d\n", GetLastError());
16714 
16715     /* Search for a Windows Key + letter combination that hasn't been registered */
16716     for (hotkey_letter = 0x41; hotkey_letter <= 0x51; hotkey_letter ++)
16717     {
16718         SetLastError(0xdeadbeef);
16719         ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
16720 
16721         if (ret == TRUE)
16722         {
16723             break;
16724         }
16725         else
16726         {
16727             ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16728                "unexpected error %d\n", GetLastError());
16729         }
16730     }
16731 
16732     if (hotkey_letter == 0x52)
16733     {
16734         ok(0, "Couldn't find any free Windows Key + letter combination\n");
16735         goto end;
16736     }
16737 
16738     hKBD_hook = SetWindowsHookExA(WH_KEYBOARD_LL, KeyboardHookProc, GetModuleHandleA(NULL), 0);
16739     if (!hKBD_hook) win_skip("WH_KEYBOARD_LL is not supported\n");
16740 
16741     /* Same key combination, different id */
16742     SetLastError(0xdeadbeef);
16743     ret = RegisterHotKey(test_window, 4, MOD_WIN, hotkey_letter);
16744     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16745     ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16746        "unexpected error %d\n", GetLastError());
16747 
16748     /* Same key combination, different window */
16749     SetLastError(0xdeadbeef);
16750     ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
16751     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16752     ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16753        "unexpected error %d\n", GetLastError());
16754 
16755     /* Register the same hotkey twice */
16756     SetLastError(0xdeadbeef);
16757     ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
16758     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16759     ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16760        "unexpected error %d\n", GetLastError());
16761 
16762     /* Window on another thread */
16763     taskbar_window = FindWindowA("Shell_TrayWnd", NULL);
16764     if (!taskbar_window)
16765     {
16766         skip("no taskbar?\n");
16767     }
16768     else
16769     {
16770         SetLastError(0xdeadbeef);
16771         ret = RegisterHotKey(taskbar_window, 5, 0, hotkey_letter);
16772         ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16773         ok(GetLastError() == ERROR_WINDOW_OF_OTHER_THREAD || broken(GetLastError() == 0xdeadbeef),
16774            "unexpected error %d\n", GetLastError());
16775     }
16776 
16777     /* Inject the appropriate key sequence */
16778     keybd_event(VK_LWIN, 0, 0, 0);
16779     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16780         DispatchMessageA(&msg);
16781     ok_sequence(WmHotkeyPressLWIN, "window hotkey press LWIN", FALSE);
16782 
16783     keybd_event(hotkey_letter, 0, 0, 0);
16784     queue_status = GetQueueStatus(QS_HOTKEY);
16785     ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
16786     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16787     {
16788         if (msg.message == WM_HOTKEY)
16789         {
16790             ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
16791             ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
16792         }
16793         DispatchMessageA(&msg);
16794     }
16795     ok_sequence(WmHotkeyPress, "window hotkey press", FALSE);
16796 
16797     queue_status = GetQueueStatus(QS_HOTKEY);
16798     ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
16799 
16800     key_state = GetAsyncKeyState(hotkey_letter);
16801     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16802 
16803     keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16804     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16805         DispatchMessageA(&msg);
16806     ok_sequence(WmHotkeyRelease, "window hotkey release", TRUE);
16807 
16808     keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
16809     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16810         DispatchMessageA(&msg);
16811     ok_sequence(WmHotkeyReleaseLWIN, "window hotkey release LWIN", FALSE);
16812 
16813     /* normal posted WM_HOTKEY messages set QS_HOTKEY */
16814     PostMessageA(test_window, WM_HOTKEY, 0, 0);
16815     queue_status = GetQueueStatus(QS_HOTKEY);
16816     ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
16817     queue_status = GetQueueStatus(QS_POSTMESSAGE);
16818     ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
16819     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16820         DispatchMessageA(&msg);
16821     flush_sequence();
16822 
16823     /* Send and process all messages at once */
16824     PostMessageA(test_window, WM_APP, 0, 0);
16825     keybd_event(VK_LWIN, 0, 0, 0);
16826     keybd_event(hotkey_letter, 0, 0, 0);
16827     keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16828     keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
16829 
16830     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16831     {
16832         if (msg.message == WM_HOTKEY)
16833         {
16834             ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
16835             ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
16836         }
16837         DispatchMessageA(&msg);
16838     }
16839     ok_sequence(WmHotkeyCombined, "window hotkey combined", FALSE);
16840 
16841     /* Register same hwnd/id with different key combination */
16842     ret = RegisterHotKey(test_window, 5, 0, hotkey_letter);
16843     ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
16844 
16845     /* Previous key combination does not work */
16846     keybd_event(VK_LWIN, 0, 0, 0);
16847     keybd_event(hotkey_letter, 0, 0, 0);
16848     keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16849     keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
16850 
16851     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16852         DispatchMessageA(&msg);
16853     ok_sequence(WmHotkeyPrevious, "window hotkey previous", FALSE);
16854 
16855     /* New key combination works */
16856     keybd_event(hotkey_letter, 0, 0, 0);
16857     keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16858 
16859     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16860     {
16861         if (msg.message == WM_HOTKEY)
16862         {
16863             ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
16864             ok(msg.lParam == MAKELPARAM(0, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
16865         }
16866         DispatchMessageA(&msg);
16867     }
16868     ok_sequence(WmHotkeyNew, "window hotkey new", FALSE);
16869 
16870     /* Unregister hotkey properly */
16871     ret = UnregisterHotKey(test_window, 5);
16872     ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
16873 
16874     /* Unregister hotkey again */
16875     SetLastError(0xdeadbeef);
16876     ret = UnregisterHotKey(test_window, 5);
16877     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16878     ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16879        "unexpected error %d\n", GetLastError());
16880 
16881     /* Register thread hotkey */
16882     ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
16883     ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
16884 
16885     /* Inject the appropriate key sequence */
16886     keybd_event(VK_LWIN, 0, 0, 0);
16887     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16888     {
16889         ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
16890         DispatchMessageA(&msg);
16891     }
16892     ok_sequence(WmHotkeyPressLWIN, "thread hotkey press LWIN", FALSE);
16893 
16894     keybd_event(hotkey_letter, 0, 0, 0);
16895     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16896     {
16897         if (msg.message == WM_HOTKEY)
16898         {
16899             struct recvd_message message;
16900             ok(msg.hwnd == NULL, "unexpected hwnd %p\n", msg.hwnd);
16901             ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
16902             message.message = msg.message;
16903             message.flags = sent|wparam|lparam;
16904             message.wParam = msg.wParam;
16905             message.lParam = msg.lParam;
16906             message.descr = "test_hotkey thread message";
16907             add_message(&message);
16908         }
16909         else
16910             ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
16911         DispatchMessageA(&msg);
16912     }
16913     ok_sequence(WmHotkeyPress, "thread hotkey press", FALSE);
16914 
16915     keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16916     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16917     {
16918         ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
16919         DispatchMessageA(&msg);
16920     }
16921     ok_sequence(WmHotkeyRelease, "thread hotkey release", TRUE);
16922 
16923     keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
16924     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16925     {
16926         ros_skip_flaky
16927         ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
16928         DispatchMessageA(&msg);
16929     }
16930     ok_sequence(WmHotkeyReleaseLWIN, "thread hotkey release LWIN", FALSE);
16931 
16932     /* Unregister thread hotkey */
16933     ret = UnregisterHotKey(NULL, 5);
16934     ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
16935 
16936     if (hKBD_hook) UnhookWindowsHookEx(hKBD_hook);
16937     hKBD_hook = NULL;
16938 
16939 end:
16940     UnregisterHotKey(NULL, 5);
16941     UnregisterHotKey(test_window, 5);
16942     DestroyWindow(test_window);
16943     flush_sequence();
16944 }
16945 
16946 
16947 static const struct message WmSetFocus_1[] = {
16948     { HCBT_SETFOCUS, hook }, /* child */
16949     { HCBT_ACTIVATE, hook }, /* parent */
16950     { WM_QUERYNEWPALETTE, sent|wparam|lparam|parent|optional, 0, 0 },
16951     { WM_WINDOWPOSCHANGING, sent|parent, 0, SWP_NOSIZE|SWP_NOMOVE },
16952     { WM_ACTIVATEAPP, sent|wparam|parent, 1 },
16953     { WM_NCACTIVATE, sent|parent },
16954     { WM_GETTEXT, sent|defwinproc|parent|optional },
16955     { WM_GETTEXT, sent|defwinproc|parent|optional },
16956     { WM_ACTIVATE, sent|wparam|parent, 1 },
16957     { HCBT_SETFOCUS, hook }, /* parent */
16958     { WM_SETFOCUS, sent|defwinproc|parent },
16959     { WM_KILLFOCUS, sent|parent },
16960     { WM_SETFOCUS, sent },
16961     { 0 }
16962 };
16963 static const struct message WmSetFocus_2[] = {
16964     { HCBT_SETFOCUS, hook }, /* parent */
16965     { WM_KILLFOCUS, sent },
16966     { WM_SETFOCUS, sent|parent },
16967     { 0 }
16968 };
16969 static const struct message WmSetFocus_3[] = {
16970     { HCBT_SETFOCUS, hook }, /* child */
16971     { 0 }
16972 };
16973 
16974 static void test_SetFocus(void)
16975 {
16976     HWND parent, old_parent, child, old_focus, old_active;
16977     MSG msg;
16978     struct wnd_event wnd_event;
16979     HANDLE hthread;
16980     DWORD ret, tid;
16981 
16982     wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
16983     ok(wnd_event.start_event != 0, "CreateEvent error %d\n", GetLastError());
16984     hthread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
16985     ok(hthread != 0, "CreateThread error %d\n", GetLastError());
16986     ret = WaitForSingleObject(wnd_event.start_event, INFINITE);
16987     ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
16988     CloseHandle(wnd_event.start_event);
16989 
16990     parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
16991                             0, 0, 0, 0, 0, 0, 0, NULL);
16992     ok(parent != 0, "failed to create parent window\n");
16993     child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
16994                            0, 0, 0, 0, parent, 0, 0, NULL);
16995     ok(child != 0, "failed to create child window\n");
16996 
16997     trace("parent %p, child %p, thread window %p\n", parent, child, wnd_event.hwnd);
16998 
16999     SetFocus(0);
17000     SetActiveWindow(0);
17001 
17002     flush_events();
17003     flush_sequence();
17004 
17005     ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
17006     ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
17007 
17008     log_all_parent_messages++;
17009 
17010     old_focus = SetFocus(child);
17011     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17012     ok_sequence(WmSetFocus_1, "SetFocus on a child window", TRUE);
17013     ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
17014     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17015     ok(GetFocus() == child, "expected focus %p, got %p\n", child, GetFocus());
17016 
17017     old_focus = SetFocus(parent);
17018     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17019     ok_sequence(WmSetFocus_2, "SetFocus on a parent window", FALSE);
17020     ok(old_focus == child, "expected old focus %p, got %p\n", child, old_focus);
17021     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17022     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17023 
17024     SetLastError(0xdeadbeef);
17025     old_focus = SetFocus((HWND)0xdeadbeef);
17026     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
17027        "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
17028     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17029     ok_sequence(WmEmptySeq, "SetFocus on an invalid window", FALSE);
17030     ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
17031     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17032     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17033 
17034     SetLastError(0xdeadbeef);
17035     old_focus = SetFocus(GetDesktopWindow());
17036     ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
17037        broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
17038     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17039     ok_sequence(WmEmptySeq, "SetFocus on a desktop window", TRUE);
17040     ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
17041     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17042     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17043 
17044     SetLastError(0xdeadbeef);
17045     old_focus = SetFocus(wnd_event.hwnd);
17046     ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
17047        broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
17048     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17049     ok_sequence(WmEmptySeq, "SetFocus on another thread window", TRUE);
17050     ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
17051     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17052     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17053 
17054     SetLastError(0xdeadbeef);
17055     old_active = SetActiveWindow((HWND)0xdeadbeef);
17056     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
17057        "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
17058     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17059     ok_sequence(WmEmptySeq, "SetActiveWindow on an invalid window", FALSE);
17060     ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
17061     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17062     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17063 
17064     SetLastError(0xdeadbeef);
17065     old_active = SetActiveWindow(GetDesktopWindow());
17066 todo_wine
17067     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
17068     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17069     ok_sequence(WmEmptySeq, "SetActiveWindow on a desktop window", TRUE);
17070     ok(old_active == 0, "expected old focus 0, got %p\n", old_focus);
17071     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17072     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17073 
17074     SetLastError(0xdeadbeef);
17075     old_active = SetActiveWindow(wnd_event.hwnd);
17076 todo_wine
17077     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
17078     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17079     ok_sequence(WmEmptySeq, "SetActiveWindow on another thread window", TRUE);
17080     ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
17081     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17082     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17083 
17084     SetLastError(0xdeadbeef);
17085     ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE);
17086     ok(ret, "AttachThreadInput error %d\n", GetLastError());
17087 
17088     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17089     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17090 
17091     flush_events();
17092     flush_sequence();
17093 
17094     old_focus = SetFocus(wnd_event.hwnd);
17095     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17096     ok(old_focus == wnd_event.hwnd, "expected old focus %p, got %p\n", wnd_event.hwnd, old_focus);
17097     ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
17098     ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
17099 
17100     old_focus = SetFocus(parent);
17101     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17102     ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
17103     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17104     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17105 
17106     flush_events();
17107     flush_sequence();
17108 
17109     old_active = SetActiveWindow(wnd_event.hwnd);
17110     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17111     ok(old_active == parent, "expected old focus %p, got %p\n", parent, old_active);
17112     ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
17113     ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
17114 
17115     SetLastError(0xdeadbeef);
17116     ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE);
17117     ok(ret, "AttachThreadInput error %d\n", GetLastError());
17118 
17119     ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
17120     ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
17121 
17122     old_parent = SetParent(child, GetDesktopWindow());
17123     ok(old_parent == parent, "expected old parent %p, got %p\n", parent, old_parent);
17124 
17125     ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
17126     ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
17127 
17128     old_focus = SetFocus(parent);
17129     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17130     ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
17131     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17132     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17133 
17134     flush_events();
17135     flush_sequence();
17136 
17137     SetLastError(0xdeadbeef);
17138     old_focus = SetFocus(child);
17139 todo_wine
17140     ok(GetLastError() == ERROR_INVALID_PARAMETER /* Vista+ */ ||
17141        broken(GetLastError() == 0) /* XP */ ||
17142        broken(GetLastError() == 0xdeadbeef), "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
17143     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17144     ok_sequence(WmSetFocus_3, "SetFocus on a child window", TRUE);
17145     ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
17146     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17147     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17148 
17149     SetLastError(0xdeadbeef);
17150     old_active = SetActiveWindow(child);
17151     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
17152     while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17153     ok_sequence(WmEmptySeq, "SetActiveWindow on a child window", FALSE);
17154     ok(old_active == parent, "expected old active %p, got %p\n", parent, old_active);
17155     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17156     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17157 
17158     log_all_parent_messages--;
17159 
17160     DestroyWindow(child);
17161     DestroyWindow(parent);
17162 
17163     ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
17164     ok(ret, "PostMessage(WM_QUIT) error %d\n", GetLastError());
17165     ret = WaitForSingleObject(hthread, INFINITE);
17166     ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
17167     CloseHandle(hthread);
17168 }
17169 
17170 static const struct message WmSetLayeredStyle[] = {
17171     { WM_STYLECHANGING, sent },
17172     { WM_STYLECHANGED, sent },
17173     { WM_GETTEXT, sent|defwinproc|optional },
17174     { 0 }
17175 };
17176 
17177 static const struct message WmSetLayeredStyle2[] = {
17178     { WM_STYLECHANGING, sent },
17179     { WM_STYLECHANGED, sent },
17180     { WM_WINDOWPOSCHANGING, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
17181     { WM_NCCALCSIZE, sent|optional|wparam|defwinproc, 1 },
17182     { WM_WINDOWPOSCHANGED, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
17183     { WM_MOVE, sent|optional|defwinproc|wparam, 0 },
17184     { WM_SIZE, sent|optional|defwinproc|wparam, SIZE_RESTORED },
17185     { 0 }
17186 };
17187 
17188 struct layered_window_info
17189 {
17190     HWND   hwnd;
17191     HDC    hdc;
17192     SIZE   size;
17193     HANDLE event;
17194     BOOL   ret;
17195 };
17196 
17197 static DWORD CALLBACK update_layered_proc( void *param )
17198 {
17199     struct layered_window_info *info = param;
17200     POINT src = { 0, 0 };
17201 
17202     info->ret = pUpdateLayeredWindow( info->hwnd, 0, NULL, &info->size,
17203                                       info->hdc, &src, 0, NULL, ULW_OPAQUE );
17204     ok( info->ret, "failed\n");
17205     SetEvent( info->event );
17206     return 0;
17207 }
17208 
17209 static void test_layered_window(void)
17210 {
17211     HWND hwnd;
17212     HDC hdc;
17213     HBITMAP bmp;
17214     BOOL ret;
17215     SIZE size;
17216     POINT pos, src;
17217     RECT rect, client;
17218     HANDLE thread;
17219     DWORD tid;
17220     struct layered_window_info info;
17221 
17222     if (!pUpdateLayeredWindow)
17223     {
17224         win_skip( "UpdateLayeredWindow not supported\n" );
17225         return;
17226     }
17227 
17228     hdc = CreateCompatibleDC( 0 );
17229     bmp = CreateCompatibleBitmap( hdc, 300, 300 );
17230     SelectObject( hdc, bmp );
17231 
17232     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_CAPTION | WS_THICKFRAME | WS_SYSMENU,
17233                            100, 100, 300, 300, 0, 0, 0, NULL);
17234     ok( hwnd != 0, "failed to create window\n" );
17235     ShowWindow( hwnd, SW_SHOWNORMAL );
17236     UpdateWindow( hwnd );
17237     flush_events();
17238     flush_sequence();
17239 
17240     GetWindowRect( hwnd, &rect );
17241     GetClientRect( hwnd, &client );
17242     ok( client.right < rect.right - rect.left, "wrong client area\n" );
17243     ok( client.bottom < rect.bottom - rect.top, "wrong client area\n" );
17244 
17245     src.x = src.y = 0;
17246     pos.x = pos.y = 300;
17247     size.cx = size.cy = 250;
17248     ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
17249     ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
17250     ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
17251     SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
17252     ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
17253 
17254     ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
17255     ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
17256     ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
17257     GetWindowRect( hwnd, &rect );
17258     ok( rect.left == 300 && rect.top == 300 && rect.right == 550 && rect.bottom == 550,
17259         "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
17260     GetClientRect( hwnd, &rect );
17261     ok( rect.right == client.right - 50 && rect.bottom == client.bottom - 50,
17262         "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
17263 
17264     size.cx = 150;
17265     pos.y = 200;
17266     ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
17267     ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
17268     ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
17269     GetWindowRect( hwnd, &rect );
17270     ok( rect.left == 300 && rect.top == 200 && rect.right == 450 && rect.bottom == 450,
17271         "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
17272     GetClientRect( hwnd, &rect );
17273     ok( rect.right == client.right - 150 && rect.bottom == client.bottom - 50,
17274         "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
17275 
17276     SetWindowLongA( hwnd, GWL_STYLE,
17277                    GetWindowLongA(hwnd, GWL_STYLE) & ~(WS_CAPTION | WS_THICKFRAME | WS_SYSMENU) );
17278     ok_sequence( WmSetLayeredStyle2, "WmSetLayeredStyle2", FALSE );
17279 
17280     size.cx = 200;
17281     pos.x = 200;
17282     ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
17283     ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
17284     ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
17285     GetWindowRect( hwnd, &rect );
17286     ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
17287         "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
17288     GetClientRect( hwnd, &rect );
17289     ok( (rect.right == 200 && rect.bottom == 250) ||
17290         broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
17291         "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
17292 
17293     size.cx = 0;
17294     ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
17295     ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
17296     ok( GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == ERROR_MR_MID_NOT_FOUND) ||
17297         broken(GetLastError() == ERROR_GEN_FAILURE) /* win7 */, "wrong error %u\n", GetLastError() );
17298     size.cx = 1;
17299     size.cy = -1;
17300     ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
17301     ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
17302     ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
17303 
17304     SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED );
17305     ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
17306     GetWindowRect( hwnd, &rect );
17307     ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
17308         "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
17309     GetClientRect( hwnd, &rect );
17310     ok( (rect.right == 200 && rect.bottom == 250) ||
17311         broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
17312         "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
17313 
17314     SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
17315     info.hwnd = hwnd;
17316     info.hdc = hdc;
17317     info.size.cx = 250;
17318     info.size.cy = 300;
17319     info.event = CreateEventA( NULL, TRUE, FALSE, NULL );
17320     info.ret = FALSE;
17321     thread = CreateThread( NULL, 0, update_layered_proc, &info, 0, &tid );
17322     ok( WaitForSingleObject( info.event, 1000 ) == 0, "wait failed\n" );
17323     ok( info.ret, "UpdateLayeredWindow failed in other thread\n" );
17324     WaitForSingleObject( thread, 1000 );
17325     CloseHandle( thread );
17326     GetWindowRect( hwnd, &rect );
17327     ok( rect.left == 200 && rect.top == 200 && rect.right == 450 && rect.bottom == 500,
17328         "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
17329     GetClientRect( hwnd, &rect );
17330     ok( (rect.right == 250 && rect.bottom == 300) ||
17331         broken(rect.right == client.right - 50 && rect.bottom == client.bottom),
17332         "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
17333 
17334     DestroyWindow( hwnd );
17335     DeleteDC( hdc );
17336     DeleteObject( bmp );
17337 }
17338 
17339 static HMENU hpopupmenu;
17340 
17341 static LRESULT WINAPI cancel_popup_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
17342 {
17343     if (ignore_message( message )) return 0;
17344 
17345     switch (message) {
17346     case WM_ENTERIDLE:
17347         todo_wine ok(GetCapture() == hwnd, "expected %p, got %p\n", hwnd, GetCapture());
17348         EndMenu();
17349         break;
17350     case WM_INITMENU:
17351     case WM_INITMENUPOPUP:
17352     case WM_UNINITMENUPOPUP:
17353         ok((HMENU)wParam == hpopupmenu, "expected %p, got %lx\n", hpopupmenu, wParam);
17354         break;
17355     case WM_CAPTURECHANGED:
17356         todo_wine ok(!lParam || (HWND)lParam == hwnd, "lost capture to %lx\n", lParam);
17357         break;
17358     }
17359 
17360     return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
17361 }
17362 
17363 static LRESULT WINAPI cancel_init_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
17364 {
17365     if (ignore_message( message )) return 0;
17366 
17367     switch (message) {
17368     case WM_ENTERMENULOOP:
17369         ok(EndMenu() == TRUE, "EndMenu() failed\n");
17370         break;
17371     }
17372 
17373     return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
17374 }
17375 
17376 static void test_TrackPopupMenu(void)
17377 {
17378     MSG msg;
17379     HWND hwnd;
17380     BOOL ret;
17381 
17382     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
17383                            0, 0, 1, 1, 0,
17384                            NULL, NULL, 0);
17385     ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
17386 
17387     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
17388 
17389     hpopupmenu = CreatePopupMenu();
17390     ok(hpopupmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
17391 
17392     AppendMenuA(hpopupmenu, MF_STRING, 100, "item 1");
17393     AppendMenuA(hpopupmenu, MF_STRING, 100, "item 2");
17394 
17395     flush_events();
17396     flush_sequence();
17397     ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
17398     ok_sequence(WmTrackPopupMenu, "TrackPopupMenu", TRUE);
17399     ok(ret == 1, "TrackPopupMenu failed with error %i\n", GetLastError());
17400 
17401     /* Test popup closing with an ESC-press */
17402     flush_events();
17403     PostMessageW(hwnd, WM_KEYDOWN, VK_ESCAPE, 0);
17404     ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
17405     ok(ret == 1, "TrackPopupMenu failed with error %i\n", GetLastError());
17406     PostQuitMessage(0);
17407     flush_sequence();
17408     while ( PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) )
17409     {
17410         TranslateMessage(&msg);
17411         DispatchMessageA(&msg);
17412     }
17413     ok_sequence(WmTrackPopupMenuEsc, "TrackPopupMenuEsc", FALSE); /* Shouldn't get any message */
17414 
17415     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_init_proc);
17416 
17417     flush_events();
17418     flush_sequence();
17419     ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
17420     ok_sequence(WmTrackPopupMenuAbort, "WmTrackPopupMenuAbort", TRUE);
17421     ok(ret == TRUE, "TrackPopupMenu failed\n");
17422 
17423     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
17424 
17425     SetCapture(hwnd);
17426 
17427     flush_events();
17428     flush_sequence();
17429     ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
17430     ok_sequence(WmTrackPopupMenuCapture, "TrackPopupMenuCapture", TRUE);
17431     ok(ret == 1, "TrackPopupMenuCapture failed with error %i\n", GetLastError());
17432 
17433     DestroyMenu(hpopupmenu);
17434     DestroyWindow(hwnd);
17435 }
17436 
17437 static void test_TrackPopupMenuEmpty(void)
17438 {
17439     HWND hwnd;
17440     BOOL ret;
17441 
17442     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
17443                            0, 0, 1, 1, 0,
17444                            NULL, NULL, 0);
17445     ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
17446 
17447     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
17448 
17449     hpopupmenu = CreatePopupMenu();
17450     ok(hpopupmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
17451 
17452     flush_events();
17453     flush_sequence();
17454     ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
17455     ok_sequence(WmTrackPopupMenuEmpty, "TrackPopupMenuEmpty", TRUE);
17456     ok(ret == 0, "TrackPopupMenu succeeded\n");
17457 
17458     DestroyMenu(hpopupmenu);
17459     DestroyWindow(hwnd);
17460 }
17461 
17462 static const struct message send_message_1[] = {
17463     { WM_USER+2, sent|wparam|lparam, 0, 0 },
17464     { WM_USER, sent|wparam|lparam, 0, 0 },
17465     { 0 }
17466 };
17467 static const struct message send_message_2[] = {
17468     { WM_USER+4, sent|wparam|lparam, 0, 0 },
17469     { 0 }
17470 };
17471 static const struct message send_message_3[] = {
17472     { WM_USER+3, sent|wparam|lparam, 0, 0 },
17473     { WM_USER+1, sent|wparam|lparam, 0, 0 },
17474     { 0 }
17475 };
17476 
17477 static DWORD WINAPI SendMessage_thread_1(void *param)
17478 {
17479     struct wnd_event *wnd_event = param;
17480 
17481     trace("thread: starting\n");
17482     WaitForSingleObject(wnd_event->start_event, INFINITE);
17483 
17484     trace("thread: call PostMessage\n");
17485     PostMessageA(wnd_event->hwnd, WM_USER, 0, 0);
17486 
17487     trace("thread: call PostMessage\n");
17488     PostMessageA(wnd_event->hwnd, WM_USER+1, 0, 0);
17489 
17490     trace("thread: call SendMessage\n");
17491     SendMessageA(wnd_event->hwnd, WM_USER+2, 0, 0);
17492 
17493     trace("thread: call SendMessage\n");
17494     SendMessageA(wnd_event->hwnd, WM_USER+3, 0, 0);
17495 
17496     return 0;
17497 }
17498 
17499 static DWORD WINAPI SendMessage_thread_2(void *param)
17500 {
17501     struct wnd_event *wnd_event = param;
17502 
17503     trace("thread: starting\n");
17504     WaitForSingleObject(wnd_event->start_event, INFINITE);
17505 
17506     trace("thread: call PostMessage\n");
17507     PostMessageA(wnd_event->hwnd, WM_USER, 0, 0);
17508 
17509     trace("thread: call PostMessage\n");
17510     PostMessageA(wnd_event->hwnd, WM_USER+1, 0, 0);
17511 
17512     /* this leads to sending an internal message under Wine */
17513     trace("thread: call SetParent\n");
17514     SetParent(wnd_event->hwnd, wnd_event->hwnd);
17515 
17516     trace("thread: call SendMessage\n");
17517     SendMessageA(wnd_event->hwnd, WM_USER+2, 0, 0);
17518 
17519     trace("thread: call SendMessage\n");
17520     SendMessageA(wnd_event->hwnd, WM_USER+3, 0, 0);
17521 
17522     return 0;
17523 }
17524 
17525 static void test_SendMessage_other_thread(int thread_n)
17526 {
17527     DWORD qs_all_input = QS_ALLINPUT & ~QS_RAWINPUT;
17528     HANDLE hthread;
17529     struct wnd_event wnd_event;
17530     DWORD tid, ret;
17531     MSG msg;
17532 
17533     wnd_event.start_event = CreateEventA(NULL, 0, 0, NULL);
17534 
17535     wnd_event.hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
17536                                      100, 100, 200, 200, 0, 0, 0, NULL);
17537     ok(wnd_event.hwnd != 0, "CreateWindowEx failed\n");
17538 
17539     hthread = CreateThread(NULL, 0, thread_n == 1 ? SendMessage_thread_1 : SendMessage_thread_2, &wnd_event, 0, &tid);
17540     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
17541     CloseHandle(hthread);
17542 
17543     flush_events();
17544     flush_sequence();
17545 
17546     ret = GetQueueStatus(QS_SENDMESSAGE);
17547     ok(ret == 0, "wrong status %08x\n", ret);
17548 
17549     SetEvent(wnd_event.start_event);
17550 
17551     /* wait for other thread's SendMessage */
17552     for (;;)
17553     {
17554         ret = GetQueueStatus(QS_SENDMESSAGE);
17555         if (ret == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE)) break;
17556         Sleep(50);
17557     }
17558 
17559     ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17560     ok(ret == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE), "wrong status %08x\n", ret);
17561 
17562     trace("main: call GetMessage\n");
17563     GetMessageA(&msg, 0, 0, 0);
17564     ok(msg.message == WM_USER, "expected WM_USER, got %04x\n", msg.message);
17565     DispatchMessageA(&msg);
17566     ok_sequence(send_message_1, "SendMessage from other thread 1", thread_n == 2);
17567 
17568     /* intentionally yield */
17569     MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input);
17570 
17571     trace("main: call SendMessage\n");
17572     SendMessageA(wnd_event.hwnd, WM_USER+4, 0, 0);
17573     ok_sequence(send_message_2, "SendMessage from other thread 2", FALSE);
17574 
17575     ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17576     ok(ret == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE), "wrong status %08x\n", ret);
17577 
17578     trace("main: call PeekMessage\n");
17579     ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should not fail\n");
17580     ok(msg.message == WM_USER+1, "expected WM_USER+1, got %04x\n", msg.message);
17581     DispatchMessageA(&msg);
17582     ok_sequence(send_message_3, "SendMessage from other thread 3", thread_n == 2);
17583 
17584     /* intentionally yield */
17585     MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input);
17586 
17587     ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17588     /* FIXME: remove once Wine is fixed */
17589 todo_wine_if (thread_n == 2)
17590     ok(ret == 0, "wrong status %08x\n", ret);
17591 
17592     trace("main: call PeekMessage\n");
17593     ok(!PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should fail\n");
17594     ok_sequence(WmEmptySeq, "SendMessage from other thread 5", thread_n == 2);
17595 
17596     ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17597     ok(ret == 0, "wrong status %08x\n", ret);
17598 
17599     trace("main: call DestroyWindow\n");
17600     DestroyWindow(msg.hwnd);
17601 
17602     flush_events();
17603     flush_sequence();
17604 }
17605 
17606 static LRESULT CALLBACK insendmessage_wnd_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
17607 {
17608     DWORD flags = InSendMessageEx( NULL );
17609     BOOL ret;
17610 
17611     switch (msg)
17612     {
17613     case WM_USER:
17614         ok( flags == ISMEX_SEND, "wrong flags %x\n", flags );
17615         ok( InSendMessage(), "InSendMessage returned false\n" );
17616         ret = ReplyMessage( msg );
17617         ok( ret, "ReplyMessage failed err %u\n", GetLastError() );
17618         flags = InSendMessageEx( NULL );
17619         ok( flags == (ISMEX_SEND | ISMEX_REPLIED), "wrong flags %x\n", flags );
17620         ok( InSendMessage(), "InSendMessage returned false\n" );
17621         break;
17622     case WM_USER + 1:
17623         ok( flags == ISMEX_NOTIFY, "wrong flags %x\n", flags );
17624         ok( InSendMessage(), "InSendMessage returned false\n" );
17625         ret = ReplyMessage( msg );
17626         ok( ret, "ReplyMessage failed err %u\n", GetLastError() );
17627         flags = InSendMessageEx( NULL );
17628         ok( flags == ISMEX_NOTIFY, "wrong flags %x\n", flags );
17629         ok( InSendMessage(), "InSendMessage returned false\n" );
17630         break;
17631     case WM_USER + 2:
17632         ok( flags == ISMEX_CALLBACK, "wrong flags %x\n", flags );
17633         ok( InSendMessage(), "InSendMessage returned false\n" );
17634         ret = ReplyMessage( msg );
17635         ok( ret, "ReplyMessage failed err %u\n", GetLastError() );
17636         flags = InSendMessageEx( NULL );
17637         ok( flags == (ISMEX_CALLBACK | ISMEX_REPLIED) || flags == ISMEX_SEND, "wrong flags %x\n", flags );
17638         ok( InSendMessage(), "InSendMessage returned false\n" );
17639         break;
17640     case WM_USER + 3:
17641         ok( flags == ISMEX_NOSEND, "wrong flags %x\n", flags );
17642         ok( !InSendMessage(), "InSendMessage returned true\n" );
17643         ret = ReplyMessage( msg );
17644         ok( !ret, "ReplyMessage succeeded\n" );
17645         break;
17646     }
17647 
17648     return DefWindowProcA( hwnd, msg, wp, lp );
17649 }
17650 
17651 static void CALLBACK msg_callback( HWND hwnd, UINT msg, ULONG_PTR arg, LRESULT result )
17652 {
17653     ok( msg == WM_USER + 2, "wrong msg %x\n", msg );
17654     ok( result == WM_USER + 2, "wrong result %lx\n", result );
17655 }
17656 
17657 static DWORD WINAPI send_message_thread( void *arg )
17658 {
17659     HWND win = arg;
17660 
17661     SendMessageA( win, WM_USER, 0, 0 );
17662     SendNotifyMessageA( win, WM_USER + 1, 0, 0 );
17663     SendMessageCallbackA( win, WM_USER + 2, 0, 0, msg_callback, 0 );
17664     PostMessageA( win, WM_USER + 3, 0, 0 );
17665     PostMessageA( win, WM_QUIT, 0, 0 );
17666     return 0;
17667 }
17668 
17669 static void test_InSendMessage(void)
17670 {
17671     WNDCLASSA cls;
17672     HWND win;
17673     MSG msg;
17674     HANDLE thread;
17675     DWORD tid;
17676 
17677     memset(&cls, 0, sizeof(cls));
17678     cls.lpfnWndProc = insendmessage_wnd_proc;
17679     cls.hInstance = GetModuleHandleA(NULL);
17680     cls.lpszClassName = "InSendMessage_test";
17681     RegisterClassA(&cls);
17682 
17683     win = CreateWindowA( "InSendMessage_test", NULL, 0, 0, 0, 0, 0, NULL, 0, NULL, 0 );
17684     ok( win != NULL, "CreateWindow failed: %d\n", GetLastError() );
17685 
17686     thread = CreateThread( NULL, 0, send_message_thread, win, 0, &tid );
17687     ok( thread != NULL, "CreateThread failed: %d\n", GetLastError() );
17688 
17689     while (GetMessageA(&msg, NULL, 0, 0)) DispatchMessageA( &msg );
17690 
17691     ok( WaitForSingleObject( thread, 30000 ) == WAIT_OBJECT_0, "WaitForSingleObject failed\n" );
17692     CloseHandle( thread );
17693 
17694     DestroyWindow( win );
17695     UnregisterClassA( "InSendMessage_test", GetModuleHandleA(NULL) );
17696 }
17697 
17698 static const struct message DoubleSetCaptureSeq[] =
17699 {
17700     { WM_CAPTURECHANGED, sent },
17701     { 0 }
17702 };
17703 
17704 static void test_DoubleSetCapture(void)
17705 {
17706     HWND hwnd;
17707 
17708     hwnd = CreateWindowExA(0, "TestWindowClass", "Test DoubleSetCapture",
17709                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
17710                            100, 100, 200, 200, 0, 0, 0, NULL);
17711     ok (hwnd != 0, "Failed to create overlapped window\n");
17712 
17713     ShowWindow( hwnd, SW_SHOW );
17714     UpdateWindow( hwnd );
17715     flush_events();
17716     flush_sequence();
17717 
17718     SetCapture( hwnd );
17719     SetCapture( hwnd );
17720     ok_sequence(DoubleSetCaptureSeq, "SetCapture( hwnd ) twice", FALSE);
17721 
17722     DestroyWindow(hwnd);
17723 }
17724 
17725 static const struct message WmRestoreMinimizedSeq[] =
17726 {
17727     { HCBT_ACTIVATE, hook },
17728     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
17729     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
17730     { WM_ACTIVATEAPP, sent|wparam, 1 },
17731     { WM_NCACTIVATE, sent|wparam, 0x200001 },
17732     { WM_GETTEXT, sent|defwinproc|optional },
17733     { WM_ACTIVATE, sent|wparam, 0x200001 }, /* Note that activate messages are after WM_WINDOWPOSCHANGED and before WM_SYSCOMMAND */
17734     { HCBT_KEYSKIPPED, hook|optional },
17735     { WM_SYSKEYUP, sent|optional },
17736     { WM_SYSCOMMAND, sent|wparam, SC_RESTORE },
17737     { HCBT_SYSCOMMAND, hook|wparam, SC_RESTORE },
17738     { HCBT_SYSCOMMAND, hook|wparam|optional, SC_RESTORE },
17739     { HCBT_MINMAX, hook },
17740     { HCBT_MINMAX, hook|optional },
17741     { WM_QUERYOPEN, sent|defwinproc },
17742     { WM_QUERYOPEN, sent|optional },
17743     { WM_GETTEXT, sent|defwinproc|optional },
17744     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
17745     { WM_GETMINMAXINFO, sent|defwinproc },
17746     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
17747     { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
17748     { WM_GETTEXT, sent|defwinproc|optional },
17749     { WM_ERASEBKGND, sent|defwinproc },
17750     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
17751     { WM_MOVE, sent|defwinproc },
17752     { WM_SIZE, sent|defwinproc },
17753     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
17754     { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
17755     { WM_ERASEBKGND, sent|defwinproc|optional },
17756     { HCBT_SETFOCUS, hook },
17757     { WM_SETFOCUS, sent|defwinproc },
17758     { WM_ACTIVATE, sent|wparam|defwinproc, 1 },
17759     { WM_PAINT, sent| optional },
17760     { WM_SETFOCUS, sent|defwinproc|optional },
17761     { HCBT_KEYSKIPPED, hook|optional },
17762     { WM_KEYUP, sent|optional },
17763     { HCBT_KEYSKIPPED, hook|optional },
17764     { WM_SYSKEYUP, sent|optional },
17765     { HCBT_KEYSKIPPED, hook|optional },
17766     { WM_KEYUP, sent|optional },
17767     { WM_PAINT, sent| optional },
17768     { 0 }
17769 };
17770 
17771 static void test_restore_messages(void)
17772 {
17773     INPUT ip = {0};
17774     HWND hwnd;
17775     INT i;
17776 
17777     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100,
17778                            100, 200, 200, 0, 0, 0, NULL);
17779     ok (hwnd != 0, "Failed to create overlapped window\n");
17780     SetForegroundWindow(hwnd);
17781     ShowWindow(hwnd, SW_MINIMIZE);
17782     flush_events();
17783     flush_sequence();
17784 
17785     for (i = 0; i < 5; i++)
17786     {
17787         /* Send Alt+Tab to restore test window from minimized state */
17788         ip.type = INPUT_KEYBOARD;
17789         ip.ki.wVk = VK_MENU;
17790         SendInput(1, &ip, sizeof(INPUT));
17791         ip.ki.wVk = VK_TAB;
17792         SendInput(1, &ip, sizeof(INPUT));
17793         ip.ki.wVk = VK_MENU;
17794         ip.ki.dwFlags = KEYEVENTF_KEYUP;
17795         SendInput(1, &ip, sizeof(INPUT));
17796         ip.ki.wVk = VK_TAB;
17797         ip.ki.dwFlags = KEYEVENTF_KEYUP;
17798         SendInput(1, &ip, sizeof(INPUT));
17799         flush_events();
17800         if (!IsIconic(hwnd))
17801             break;
17802     }
17803 
17804     if (IsIconic(hwnd))
17805     {
17806         skip("Alt+Tab failed to bring up test window.\n");
17807         goto done;
17808     }
17809     ok_sequence(WmRestoreMinimizedSeq, "Restore minimized window", TRUE);
17810 
17811 done:
17812     DestroyWindow(hwnd);
17813 }
17814 
17815 static void test_invalid_window(void)
17816 {
17817     MSG msg;
17818     BOOL ret;
17819 
17820     SetLastError(0xdeadbeef);
17821     ret = GetMessageA(&msg, (HWND)0xdeadbeef, 0, 0);
17822     ok(ret == -1, "wrong ret %d\n", ret);
17823     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError());
17824 
17825     SetLastError(0xdeadbeef);
17826     ret = PeekMessageA(&msg, (HWND)0xdeadbeef, 0, 0, PM_REMOVE);
17827     ok(!ret, "wrong ret %d\n", ret);
17828     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError());
17829 }
17830 
17831 static void init_funcs(void)
17832 {
17833     HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
17834 
17835 #define X(f) p##f = (void*)GetProcAddress(hKernel32, #f)
17836     X(ActivateActCtx);
17837     X(CreateActCtxW);
17838     X(DeactivateActCtx);
17839     X(GetCurrentActCtx);
17840     X(QueryActCtxW);
17841     X(ReleaseActCtx);
17842 #undef X
17843 }
17844 
17845 #ifndef __REACTOS__
17846 START_TEST(msg)
17847 {
17848     char **test_argv;
17849     BOOL ret;
17850     BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
17851     HMODULE hModuleImm32;
17852     BOOL (WINAPI *pImmDisableIME)(DWORD);
17853     int argc;
17854 
17855     init_funcs();
17856 
17857     argc = winetest_get_mainargs( &test_argv );
17858     if (argc >= 3)
17859     {
17860         unsigned int arg;
17861         /* Child process. */
17862         sscanf (test_argv[2], "%d", (unsigned int *) &arg);
17863         do_wait_idle_child( arg );
17864         return;
17865     }
17866 
17867     InitializeCriticalSection( &sequence_cs );
17868     init_procs();
17869 
17870     hModuleImm32 = LoadLibraryA("imm32.dll");
17871     if (hModuleImm32) {
17872         pImmDisableIME = (void *)GetProcAddress(hModuleImm32, "ImmDisableIME");
17873         if (pImmDisableIME)
17874             pImmDisableIME(0);
17875     }
17876     pImmDisableIME = NULL;
17877     FreeLibrary(hModuleImm32);
17878 
17879     if (!RegisterWindowClasses()) assert(0);
17880 
17881     if (pSetWinEventHook)
17882     {
17883         hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
17884                                        GetModuleHandleA(0), win_event_proc,
17885                                        0, GetCurrentThreadId(),
17886                                        WINEVENT_INCONTEXT);
17887         if (pIsWinEventHookInstalled && hEvent_hook)
17888 	{
17889 	    UINT event;
17890 	    for (event = EVENT_MIN; event <= EVENT_MAX; event++)
17891 		ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
17892 	}
17893     }
17894     if (!hEvent_hook) win_skip( "no win event hook support\n" );
17895 
17896     cbt_hook_thread_id = GetCurrentThreadId();
17897     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
17898     if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
17899 
17900     test_winevents();
17901 
17902     /* Fix message sequences before removing 4 lines below */
17903     if (pUnhookWinEvent && hEvent_hook)
17904     {
17905         ret = pUnhookWinEvent(hEvent_hook);
17906         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
17907         pUnhookWinEvent = 0;
17908     }
17909     hEvent_hook = 0;
17910 
17911     test_SendMessage_other_thread(1);
17912     test_SendMessage_other_thread(2);
17913     test_InSendMessage();
17914     test_SetFocus();
17915     test_SetParent();
17916     test_PostMessage();
17917     test_broadcast();
17918     test_ShowWindow();
17919     test_PeekMessage();
17920     test_PeekMessage2();
17921     test_PeekMessage3();
17922     test_WaitForInputIdle( test_argv[0] );
17923     test_scrollwindowex();
17924     test_messages();
17925     test_setwindowpos();
17926     test_showwindow();
17927     test_recursive_activation();
17928     invisible_parent_tests();
17929     test_mdi_messages();
17930     test_button_messages();
17931     test_button_bm_get_set_image();
17932     test_autoradio_BM_CLICK();
17933     test_autoradio_kbd_move();
17934     test_static_messages();
17935     test_listbox_messages();
17936     test_combobox_messages();
17937     test_wmime_keydown_message();
17938     test_paint_messages();
17939     test_interthread_messages();
17940     test_message_conversion();
17941     test_accelerators();
17942     test_timers();
17943     test_timers_no_wnd();
17944     test_timers_exceptions();
17945     if (hCBT_hook)
17946     {
17947         test_set_hook();
17948         test_recursive_hook();
17949     }
17950     test_DestroyWindow();
17951     test_DispatchMessage();
17952     test_SendMessageTimeout();
17953     test_edit_messages();
17954     test_quit_message();
17955     test_notify_message();
17956     test_SetActiveWindow();
17957     test_restore_messages();
17958     test_invalid_window();
17959 
17960     if (!pTrackMouseEvent)
17961         win_skip("TrackMouseEvent is not available\n");
17962     else
17963         test_TrackMouseEvent();
17964 
17965     test_SetWindowRgn();
17966     test_sys_menu();
17967     test_dialog_messages();
17968     test_EndDialog();
17969     test_nullCallback();
17970     test_dbcs_wm_char();
17971     test_unicode_wm_char();
17972     test_menu_messages();
17973     test_paintingloop();
17974     test_defwinproc();
17975     test_desktop_winproc();
17976     test_clipboard_viewers();
17977     test_keyflags();
17978     test_hotkey();
17979     test_layered_window();
17980     test_TrackPopupMenu();
17981     test_TrackPopupMenuEmpty();
17982     test_DoubleSetCapture();
17983     /* keep it the last test, under Windows it tends to break the tests
17984      * which rely on active/foreground windows being correct.
17985      */
17986     test_SetForegroundWindow();
17987 
17988     UnhookWindowsHookEx(hCBT_hook);
17989     if (pUnhookWinEvent && hEvent_hook)
17990     {
17991 	ret = pUnhookWinEvent(hEvent_hook);
17992 	ok( ret, "UnhookWinEvent error %d\n", GetLastError());
17993 	SetLastError(0xdeadbeef);
17994 	ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
17995 	ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
17996 	   GetLastError() == 0xdeadbeef, /* Win9x */
17997            "unexpected error %d\n", GetLastError());
17998     }
17999     DeleteCriticalSection( &sequence_cs );
18000 }
18001 #endif /* __REACTOS__ */
18002 
18003 static void init_tests()
18004 {
18005     HMODULE hModuleImm32;
18006     BOOL (WINAPI *pImmDisableIME)(DWORD);
18007 
18008     init_funcs();
18009 
18010     InitializeCriticalSection( &sequence_cs );
18011     init_procs();
18012 
18013     hModuleImm32 = LoadLibraryA("imm32.dll");
18014     if (hModuleImm32) {
18015         pImmDisableIME = (void *)GetProcAddress(hModuleImm32, "ImmDisableIME");
18016         if (pImmDisableIME)
18017             pImmDisableIME(0);
18018     }
18019     pImmDisableIME = NULL;
18020     FreeLibrary(hModuleImm32);
18021 
18022     if (!RegisterWindowClasses()) assert(0);
18023 
18024     cbt_hook_thread_id = GetCurrentThreadId();
18025     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
18026     if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
18027 }
18028 
18029 static void cleanup_tests()
18030 {
18031     BOOL ret;
18032     UnhookWindowsHookEx(hCBT_hook);
18033     if (pUnhookWinEvent && hEvent_hook)
18034     {
18035         ret = pUnhookWinEvent(hEvent_hook);
18036         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
18037         SetLastError(0xdeadbeef);
18038         ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
18039         ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
18040            GetLastError() == 0xdeadbeef, /* Win9x */
18041            "unexpected error %d\n", GetLastError());
18042     }
18043     DeleteCriticalSection( &sequence_cs );
18044 
18045 }
18046 
18047 START_TEST(msg_queue)
18048 {
18049     int argc;
18050     char **test_argv;
18051     argc = winetest_get_mainargs( &test_argv );
18052     if (argc >= 3)
18053     {
18054         unsigned int arg;
18055         /* Child process. */
18056         sscanf (test_argv[2], "%d", (unsigned int *) &arg);
18057         do_wait_idle_child( arg );
18058         return;
18059     }
18060 
18061     init_tests();
18062     test_SendMessage_other_thread(1);
18063     test_SendMessage_other_thread(2);
18064     test_InSendMessage();
18065     test_PostMessage();
18066     test_broadcast();
18067     test_PeekMessage();
18068     test_PeekMessage2();
18069     test_PeekMessage3();
18070     test_interthread_messages();
18071     test_DispatchMessage();
18072     test_SendMessageTimeout();
18073     test_quit_message();
18074     test_notify_message();
18075     test_WaitForInputIdle( test_argv[0] );
18076     test_DestroyWindow();
18077     cleanup_tests();
18078 }
18079 
18080 START_TEST(msg_messages)
18081 {
18082     init_tests();
18083     test_message_conversion();
18084     test_messages();
18085     test_wmime_keydown_message();
18086     test_nullCallback();
18087     test_dbcs_wm_char();
18088     test_unicode_wm_char();
18089     test_defwinproc();
18090     test_desktop_winproc();
18091     cleanup_tests();
18092 }
18093 
18094 START_TEST(msg_focus)
18095 {
18096     init_tests();
18097 
18098     test_SetFocus();
18099 
18100     /* HACK: For some reason the tests fail on Windows if run consecutively.
18101      * Putting these in between helps, and is essentially what happens in the
18102      * "normal" msg test. */
18103     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
18104     flush_events();
18105 
18106     test_SetActiveWindow();
18107 
18108     /* HACK */
18109     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
18110     flush_events();
18111 
18112     test_restore_messages();
18113     test_invalid_window();
18114 
18115     test_DoubleSetCapture();
18116 
18117     /* keep it the last test, under Windows it tends to break the tests
18118      * which rely on active/foreground windows being correct.
18119      */
18120     test_SetForegroundWindow();
18121     cleanup_tests();
18122 }
18123 
18124 START_TEST(msg_winpos)
18125 {
18126     init_tests();
18127     test_SetParent();
18128     test_ShowWindow();
18129     test_setwindowpos();
18130     test_showwindow();
18131     test_recursive_activation();
18132     test_SetWindowRgn();
18133     invisible_parent_tests();
18134     cleanup_tests();
18135 }
18136 
18137 START_TEST(msg_paint)
18138 {
18139     init_tests();
18140     test_scrollwindowex();
18141     test_paint_messages();
18142 #ifdef __REACTOS__
18143     if (!winetest_interactive &&
18144         !strcmp(winetest_platform, "windows"))
18145     {
18146         skip("ROSTESTS-185: Skipping user32_winetest:msg_paint test_paintingloop because it hangs on WHS-Testbot. Set winetest_interactive to run it anyway.\n");
18147     }
18148     else
18149 #endif
18150     test_paintingloop();
18151     cleanup_tests();
18152 }
18153 
18154 START_TEST(msg_input)
18155 {
18156     init_tests();
18157     test_accelerators();
18158     if (!pTrackMouseEvent)
18159         win_skip("TrackMouseEvent is not available\n");
18160     else
18161         test_TrackMouseEvent();
18162 
18163     test_keyflags();
18164     test_hotkey();
18165     cleanup_tests();
18166 }
18167 
18168 START_TEST(msg_timer)
18169 {
18170     init_tests();
18171     test_timers();
18172     test_timers_no_wnd();
18173     test_timers_exceptions();
18174     cleanup_tests();
18175 }
18176 
18177 typedef BOOL (WINAPI *IS_WINEVENT_HOOK_INSTALLED)(DWORD);
18178 
18179 START_TEST(msg_hook)
18180 {
18181 //    HMODULE user32 = GetModuleHandleA("user32.dll");
18182 //    IS_WINEVENT_HOOK_INSTALLED pIsWinEventHookInstalled = (IS_WINEVENT_HOOK_INSTALLED)GetProcAddress(user32, "IsWinEventHookInstalled");
18183     BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
18184 
18185     init_tests();
18186 
18187     if (pSetWinEventHook)
18188     {
18189         hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
18190                                        GetModuleHandleA(0), win_event_proc,
18191                                        0, GetCurrentThreadId(),
18192                                        WINEVENT_INCONTEXT);
18193         if (pIsWinEventHookInstalled && hEvent_hook)
18194         {
18195             UINT event;
18196             for (event = EVENT_MIN; event <= EVENT_MAX; event++)
18197                 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
18198         }
18199     }
18200     if (!hEvent_hook) win_skip( "no win event hook support\n" );
18201 
18202     test_winevents();
18203 
18204     /* Fix message sequences before removing 4 lines below */
18205     if (pUnhookWinEvent && hEvent_hook)
18206     {
18207         BOOL ret;
18208         ret = pUnhookWinEvent(hEvent_hook);
18209         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
18210         pUnhookWinEvent = 0;
18211     }
18212     hEvent_hook = 0;
18213     if (hCBT_hook)
18214     {
18215         test_set_hook();
18216         test_recursive_hook();
18217     }
18218     cleanup_tests();
18219 }
18220 
18221 START_TEST(msg_menu)
18222 {
18223     init_tests();
18224     test_sys_menu();
18225     test_menu_messages();
18226     test_TrackPopupMenu();
18227     test_TrackPopupMenuEmpty();
18228     cleanup_tests();
18229 }
18230 
18231 START_TEST(msg_mdi)
18232 {
18233     init_tests();
18234     test_mdi_messages();
18235     cleanup_tests();
18236 }
18237 
18238 START_TEST(msg_controls)
18239 {
18240     init_tests();
18241     test_button_messages();
18242     test_button_bm_get_set_image();
18243     test_autoradio_BM_CLICK();
18244     test_autoradio_kbd_move();
18245     test_static_messages();
18246     test_listbox_messages();
18247     test_combobox_messages();
18248     test_edit_messages();
18249     cleanup_tests();
18250 }
18251 
18252 START_TEST(msg_layered_window)
18253 {
18254     init_tests();
18255     test_layered_window();
18256     cleanup_tests();
18257 }
18258 
18259 START_TEST(msg_dialog)
18260 {
18261     init_tests();
18262     test_dialog_messages();
18263     test_EndDialog();
18264     cleanup_tests();
18265 }
18266 
18267 START_TEST(msg_clipboard)
18268 {
18269     init_tests();
18270     test_clipboard_viewers();
18271     cleanup_tests();
18272 }
18273