Release 1.5.29.
[wine] / dlls / user32 / tests / msg.c
1 /*
2  * Unit tests for window message handling
3  *
4  * Copyright 1999 Ove Kaaven
5  * Copyright 2003 Dimitrie O. Paun
6  * Copyright 2004, 2005 Dmitry Timoshkov
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #define _WIN32_WINNT 0x0600 /* For WM_CHANGEUISTATE,QS_RAWINPUT,WM_DWMxxxx */
24 #define WINVER 0x0600 /* for WM_GETTITLEBARINFOEX */
25
26 #include <assert.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "wingdi.h"
33 #include "winuser.h"
34 #include "winnls.h"
35
36 #include "wine/test.h"
37
38 #define MDI_FIRST_CHILD_ID 2004
39
40 /* undocumented SWP flags - from SDK 3.1 */
41 #define SWP_NOCLIENTSIZE        0x0800
42 #define SWP_NOCLIENTMOVE        0x1000
43 #define SWP_STATECHANGED        0x8000
44
45 #define SW_NORMALNA             0xCC    /* undoc. flag in MinMaximize */
46
47 #ifndef WM_KEYF1
48 #define WM_KEYF1 0x004d
49 #endif
50
51 #ifndef WM_SYSTIMER
52 #define WM_SYSTIMER         0x0118
53 #endif
54
55 #define WND_PARENT_ID           1
56 #define WND_POPUP_ID            2
57 #define WND_CHILD_ID            3
58
59 #ifndef WM_LBTRACKPOINT
60 #define WM_LBTRACKPOINT  0x0131
61 #endif
62
63 /* encoded DRAWITEMSTRUCT into an LPARAM */
64 typedef struct
65 {
66     union
67     {
68         struct
69         {
70             UINT type    : 4;  /* ODT_* flags */
71             UINT ctl_id  : 4;  /* Control ID */
72             UINT item_id : 4;  /* Menu item ID */
73             UINT action  : 4;  /* ODA_* flags */
74             UINT state   : 16; /* ODS_* flags */
75         } item;
76         LPARAM lp;
77     } u;
78 } DRAW_ITEM_STRUCT;
79
80 static BOOL test_DestroyWindow_flag;
81 static HWINEVENTHOOK hEvent_hook;
82 static HHOOK hKBD_hook;
83 static HHOOK hCBT_hook;
84 static DWORD cbt_hook_thread_id;
85
86 static const WCHAR testWindowClassW[] =
87 { 'T','e','s','t','W','i','n','d','o','w','C','l','a','s','s','W',0 };
88
89 /*
90 FIXME: add tests for these
91 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
92  WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
93  WS_THICKFRAME: thick border
94  WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
95  WS_BORDER (default for overlapped windows): single black border
96  none (default for child (and popup?) windows): no border
97 */
98
99 typedef enum {
100     sent=0x1,
101     posted=0x2,
102     parent=0x4,
103     wparam=0x8,
104     lparam=0x10,
105     defwinproc=0x20,
106     beginpaint=0x40,
107     optional=0x80,
108     hook=0x100,
109     winevent_hook=0x200,
110     kbd_hook=0x400
111 } msg_flags_t;
112
113 struct message {
114     UINT message;          /* the WM_* code */
115     msg_flags_t flags;     /* message props */
116     WPARAM wParam;         /* expected value of wParam */
117     LPARAM lParam;         /* expected value of lParam */
118     WPARAM wp_mask;        /* mask for wParam checks */
119     LPARAM lp_mask;        /* mask for lParam checks */
120 };
121
122 struct recvd_message {
123     UINT message;          /* the WM_* code */
124     msg_flags_t flags;     /* message props */
125     HWND hwnd;             /* window that received the message */
126     WPARAM wParam;         /* expected value of wParam */
127     LPARAM lParam;         /* expected value of lParam */
128     int line;              /* source line where logged */
129     const char *descr;     /* description for trace output */
130     char output[512];      /* trace output */
131 };
132
133 /* Empty message sequence */
134 static const struct message WmEmptySeq[] =
135 {
136     { 0 }
137 };
138 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
139 static const struct message WmCreateOverlappedSeq[] = {
140     { HCBT_CREATEWND, hook },
141     { WM_GETMINMAXINFO, sent },
142     { WM_NCCREATE, sent },
143     { WM_NCCALCSIZE, sent|wparam, 0 },
144     { 0x0093, sent|defwinproc|optional },
145     { 0x0094, sent|defwinproc|optional },
146     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
147     { WM_CREATE, sent },
148     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
149     { 0 }
150 };
151 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
152  * for a not visible overlapped window.
153  */
154 static const struct message WmSWP_ShowOverlappedSeq[] = {
155     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
156     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
157     { WM_NCPAINT, sent|wparam|optional, 1 },
158     { WM_GETTEXT, sent|defwinproc|optional },
159     { WM_ERASEBKGND, sent|optional },
160     { HCBT_ACTIVATE, hook },
161     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
162     { WM_NOTIFYFORMAT, sent|optional },
163     { WM_QUERYUISTATE, sent|optional },
164     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
165     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
166     { WM_ACTIVATEAPP, sent|wparam, 1 },
167     { WM_NCACTIVATE, sent },
168     { WM_GETTEXT, sent|defwinproc|optional },
169     { WM_ACTIVATE, sent|wparam, 1 },
170     { HCBT_SETFOCUS, hook },
171     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
172     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
173     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
174     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
175     { WM_GETTEXT, sent|optional },
176     { WM_NCPAINT, sent|wparam|optional, 1 },
177     { WM_GETTEXT, sent|defwinproc|optional },
178     { WM_ERASEBKGND, sent|optional },
179     /* Win9x adds SWP_NOZORDER below */
180     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
181     { WM_GETTEXT, sent|optional },
182     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
183     { WM_NCPAINT, sent|wparam|optional, 1 },
184     { WM_ERASEBKGND, sent|optional },
185     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
186     { WM_SYNCPAINT, sent|optional },
187     { WM_GETTITLEBARINFOEX, sent|optional },
188     { WM_PAINT, sent|optional },
189     { WM_NCPAINT, sent|beginpaint|optional },
190     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
191     { WM_ERASEBKGND, sent|beginpaint|optional },
192     { 0 }
193 };
194 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
195  * for a visible overlapped window.
196  */
197 static const struct message WmSWP_HideOverlappedSeq[] = {
198     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
199     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
200     { HCBT_ACTIVATE, hook|optional },
201     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
202     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
203     { WM_NCACTIVATE, sent|optional },
204     { WM_ACTIVATE, sent|optional },
205     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
206     { 0 }
207 };
208
209 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
210  * for a visible overlapped window.
211  */
212 static const struct message WmSWP_ResizeSeq[] = {
213     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
214     { WM_GETMINMAXINFO, sent|defwinproc },
215     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
216     { WM_NCPAINT, sent|optional },
217     { WM_GETTEXT, sent|defwinproc|optional },
218     { WM_ERASEBKGND, sent|optional },
219     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
220     { WM_SIZE, sent|defwinproc|optional },
221     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
222     { WM_NCPAINT, sent|optional },
223     { WM_GETTEXT, sent|defwinproc|optional },
224     { WM_ERASEBKGND, sent|optional },
225     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
226     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
227     { 0 }
228 };
229
230 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
231  * for a visible popup window.
232  */
233 static const struct message WmSWP_ResizePopupSeq[] = {
234     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
235     { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* Win9x */
236     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
237     { WM_NCPAINT, sent|optional },
238     { WM_GETTEXT, sent|defwinproc|optional },
239     { WM_ERASEBKGND, sent|optional },
240     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
241     { WM_SIZE, sent|defwinproc|wparam|optional, SIZE_RESTORED },
242     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
243     { WM_NCPAINT, sent|optional },
244     { WM_GETTEXT, sent|defwinproc|optional },
245     { WM_ERASEBKGND, sent|optional },
246     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
247     { 0 }
248 };
249
250 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE)
251  * for a visible overlapped window.
252  */
253 static const struct message WmSWP_MoveSeq[] = {
254     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE },
255     { WM_NCPAINT, sent|optional },
256     { WM_GETTEXT, sent|defwinproc|optional },
257     { WM_ERASEBKGND, sent|optional },
258     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
259     { WM_MOVE, sent|defwinproc|wparam, 0 },
260     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
261     { 0 }
262 };
263 /* Resize with SetWindowPos(SWP_NOZORDER)
264  * for a visible overlapped window
265  * SWP_NOZORDER is stripped by the logging code
266  */
267 static const struct message WmSWP_ResizeNoZOrder[] = {
268     { WM_WINDOWPOSCHANGING, sent|wparam, /*SWP_NOZORDER|*/SWP_NOACTIVATE },
269     { WM_GETMINMAXINFO, sent|defwinproc },
270     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
271     { WM_NCPAINT, sent|optional },
272     { WM_GETTEXT, sent|defwinproc|optional },
273     { WM_ERASEBKGND, sent|optional },
274     { WM_WINDOWPOSCHANGED, sent|wparam|optional, /*SWP_NOZORDER|*/SWP_NOACTIVATE, 0,
275       SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
276     { WM_MOVE, sent|defwinproc|optional },
277     { WM_SIZE, sent|defwinproc|optional },
278     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
279     { WM_NCPAINT, sent|optional }, /* Win9x doesn't send it */
280     { WM_GETTEXT, sent|defwinproc|optional }, /* Win9x doesn't send it */
281     { WM_ERASEBKGND, sent|optional }, /* Win9x doesn't send it */
282     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
283     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
284     { 0 }
285 };
286
287 /* Switch visible mdi children */
288 static const struct message WmSwitchChild[] = {
289     /* Switch MDI child */
290     { WM_MDIACTIVATE, sent },/* in the MDI client */
291     { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 1st MDI child */
292     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
293     { WM_CHILDACTIVATE, sent },/* in the 1st MDI child */
294     /* Deactivate 2nd MDI child */
295     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
296     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
297     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
298     /* Preparing for maximize and maximize the 1st MDI child */
299     { WM_GETMINMAXINFO, sent|defwinproc }, /* in the 1st MDI child */
300     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED }, /* in the 1st MDI child */
301     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
302     { WM_CHILDACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
303     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 1st MDI child */
304     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, /* in the 1st MDI child */
305     /* Lock redraw 2nd MDI child */
306     { WM_SETREDRAW, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
307     { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
308     /* Restore 2nd MDI child */
309     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },/* in the 2nd MDI child */
310     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
311     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
312     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 2nd MDI child */
313     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, /* in the 2nd MDI child */
314     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
315     /* Redraw 2nd MDI child */
316     { WM_SETREDRAW, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
317     /* Redraw MDI frame */
318     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },/* in MDI frame */
319     { WM_NCCALCSIZE, sent|wparam, 1 },/* in MDI frame */
320     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in MDI frame */
321     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in MDI frame */
322     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
323     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
324     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
325     { HCBT_SETFOCUS, hook },
326     { WM_KILLFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
327     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },/* in the 1st MDI child */
328     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
329     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
330     { WM_SETFOCUS, sent },/* in the MDI client */
331     { HCBT_SETFOCUS, hook },
332     { WM_KILLFOCUS, sent },/* in the MDI client */
333     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
334     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, /* in the 1st MDI child */
335     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
336     { WM_SETFOCUS, sent|defwinproc }, /* in the 1st MDI child */
337     { WM_MDIACTIVATE, sent|defwinproc },/* in the 1st MDI child */
338     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* in the 1st MDI child */
339     { 0 }
340 };
341
342 /* Switch visible not maximized mdi children */
343 static const struct message WmSwitchNotMaximizedChild[] = {
344     /* Switch not maximized MDI child */
345     { WM_MDIACTIVATE, sent },/* in the MDI client */
346     { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 2nd MDI child */
347     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
348     { WM_CHILDACTIVATE, sent },/* in the 2nd MDI child */
349     /* Deactivate 1st MDI child */
350     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
351     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
352     /* Activate 2nd MDI child */
353     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE}, /* in the 2nd MDI child */
354     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 2nd MDI child */
355     { HCBT_SETFOCUS, hook }, /* in the 1st MDI child */
356     { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
357     { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
358     { WM_IME_SETCONTEXT, sent|optional }, /* in the  MDI client */
359     { WM_SETFOCUS, sent, 0 }, /* in the  MDI client */
360     { HCBT_SETFOCUS, hook },
361     { WM_KILLFOCUS, sent }, /* in the  MDI client */
362     { WM_IME_SETCONTEXT, sent|optional }, /* in the  MDI client */
363     { WM_IME_SETCONTEXT, sent|defwinproc|optional  }, /* in the 1st MDI child */
364     { WM_SETFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
365     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
366     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in the 2nd MDI child */
367     { 0 }
368 };
369
370
371 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
372                 SWP_NOZORDER|SWP_FRAMECHANGED)
373  * for a visible overlapped window with WS_CLIPCHILDREN style set.
374  */
375 static const struct message WmSWP_FrameChanged_clip[] = {
376     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
377     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
378     { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
379     { WM_GETTEXT, sent|parent|defwinproc|optional },
380     { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
381     { WM_NCPAINT, sent }, /* wparam != 1 */
382     { WM_ERASEBKGND, sent },
383     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
384     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
385     { WM_PAINT, sent },
386     { 0 }
387 };
388 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|
389                 SWP_NOZORDER|SWP_FRAMECHANGED)
390  * for a visible overlapped window.
391  */
392 static const struct message WmSWP_FrameChangedDeferErase[] = {
393     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
394     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
395     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
396     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
397     { WM_PAINT, sent|parent|optional },
398     { WM_NCPAINT, sent|beginpaint|parent|optional }, /* wparam != 1 */
399     { WM_GETTEXT, sent|beginpaint|parent|defwinproc|optional },
400     { WM_PAINT, sent },
401     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
402     { WM_ERASEBKGND, sent|beginpaint|optional },
403     { 0 }
404 };
405
406 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
407                 SWP_NOZORDER|SWP_FRAMECHANGED)
408  * for a visible overlapped window without WS_CLIPCHILDREN style set.
409  */
410 static const struct message WmSWP_FrameChanged_noclip[] = {
411     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
412     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
413     { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
414     { WM_GETTEXT, sent|parent|defwinproc|optional },
415     { WM_ERASEBKGND, sent|parent|optional },
416     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
417     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
418     { WM_PAINT, sent },
419     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
420     { WM_ERASEBKGND, sent|beginpaint|optional },
421     { 0 }
422 };
423
424 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
425 static const struct message WmShowOverlappedSeq[] = {
426     { WM_SHOWWINDOW, sent|wparam, 1 },
427     { WM_NCPAINT, sent|wparam|optional, 1 },
428     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
429     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
430     { WM_NCPAINT, sent|wparam|optional, 1 },
431     { WM_GETTEXT, sent|defwinproc|optional },
432     { WM_ERASEBKGND, sent|optional },
433     { HCBT_ACTIVATE, hook },
434     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
435     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
436     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
437     { WM_NCPAINT, sent|wparam|optional, 1 },
438     { WM_ACTIVATEAPP, sent|wparam, 1 },
439     { WM_NCACTIVATE, sent|wparam, 1 },
440     { WM_GETTEXT, sent|defwinproc|optional },
441     { WM_ACTIVATE, sent|wparam, 1 },
442     { HCBT_SETFOCUS, hook },
443     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
444     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
445     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
446     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
447     { WM_GETTEXT, sent|optional },
448     { WM_NCPAINT, sent|wparam|optional, 1 },
449     { WM_GETTEXT, sent|defwinproc|optional },
450     { WM_ERASEBKGND, sent|optional },
451     /* Win9x adds SWP_NOZORDER below */
452     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
453     { WM_NCCALCSIZE, sent|optional },
454     { WM_GETTEXT, sent|optional },
455     { WM_NCPAINT, sent|optional },
456     { WM_ERASEBKGND, sent|optional },
457     { WM_SYNCPAINT, sent|optional },
458 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
459        * messages. Does that mean that CreateWindow doesn't set initial
460        * window dimensions for overlapped windows?
461        */
462     { WM_SIZE, sent },
463     { WM_MOVE, sent },
464 #endif
465     { WM_PAINT, sent|optional },
466     { WM_NCPAINT, sent|beginpaint|optional },
467     { 0 }
468 };
469 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible overlapped window */
470 static const struct message WmShowMaxOverlappedSeq[] = {
471     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
472     { WM_GETMINMAXINFO, sent },
473     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
474     { WM_GETMINMAXINFO, sent|defwinproc },
475     { WM_NCCALCSIZE, sent|wparam, TRUE },
476     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
477     { HCBT_ACTIVATE, hook },
478     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
479     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
480     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
481     { WM_ACTIVATEAPP, sent|wparam, 1 },
482     { WM_NCACTIVATE, sent|wparam, 1 },
483     { WM_GETTEXT, sent|defwinproc|optional },
484     { WM_ACTIVATE, sent|wparam, 1 },
485     { HCBT_SETFOCUS, hook },
486     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
487     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
488     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
489     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
490     { WM_GETTEXT, sent|optional },
491     { WM_NCPAINT, sent|wparam|optional, 1 },
492     { WM_GETTEXT, sent|defwinproc|optional },
493     { WM_ERASEBKGND, sent|optional },
494     /* Win9x adds SWP_NOZORDER below */
495     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
496     { WM_MOVE, sent|defwinproc },
497     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
498     { WM_GETTEXT, sent|optional },
499     { WM_NCCALCSIZE, sent|optional },
500     { WM_NCPAINT, sent|optional },
501     { WM_ERASEBKGND, sent|optional },
502     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
503     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
504     { WM_SYNCPAINT, sent|optional },
505     { WM_GETTITLEBARINFOEX, sent|optional },
506     { WM_PAINT, sent|optional },
507     { WM_NCPAINT, sent|beginpaint|optional },
508     { WM_ERASEBKGND, sent|beginpaint|optional },
509     { 0 }
510 };
511 /* ShowWindow(SW_RESTORE) for a not visible maximized overlapped window */
512 static const struct message WmShowRestoreMaxOverlappedSeq[] = {
513     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
514     { WM_GETTEXT, sent|optional },
515     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
516     { WM_GETMINMAXINFO, sent|defwinproc },
517     { WM_NCCALCSIZE, sent|wparam, TRUE },
518     { WM_NCPAINT, sent|optional },
519     { WM_GETTEXT, sent|defwinproc|optional },
520     { WM_ERASEBKGND, sent|optional },
521     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
522     { WM_MOVE, sent|defwinproc|optional },
523     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
524     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
525     { WM_NCPAINT, sent|optional },
526     { WM_ERASEBKGND, sent|optional },
527     { WM_PAINT, sent|optional },
528     { WM_GETTITLEBARINFOEX, sent|optional },
529     { WM_NCPAINT, sent|beginpaint|optional },
530     { WM_ERASEBKGND, sent|beginpaint|optional },
531     { 0 }
532 };
533 /* ShowWindow(SW_RESTORE) for a not visible minimized overlapped window */
534 static const struct message WmShowRestoreMinOverlappedSeq[] = {
535     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
536     { WM_QUERYOPEN, sent|optional },
537     { WM_GETTEXT, sent|optional },
538     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED|SWP_NOCOPYBITS },
539     { WM_GETMINMAXINFO, sent|defwinproc },
540     { WM_NCCALCSIZE, sent|wparam, TRUE },
541     { HCBT_ACTIVATE, hook },
542     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
543     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
544     { WM_ACTIVATEAPP, sent|wparam, 1 },
545     { WM_NCACTIVATE, sent|wparam, 1 },
546     { WM_GETTEXT, sent|defwinproc|optional },
547     { WM_ACTIVATE, sent|wparam, 1 },
548     { HCBT_SETFOCUS, hook },
549     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
550     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
551     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
552     { WM_GETTEXT, sent|optional },
553     { WM_NCPAINT, sent|wparam|optional, 1 },
554     { WM_GETTEXT, sent|defwinproc|optional },
555     { WM_ERASEBKGND, sent },
556     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_STATECHANGED|SWP_FRAMECHANGED|SWP_NOCOPYBITS },
557     { WM_MOVE, sent|defwinproc },
558     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
559     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
560     { WM_NCPAINT, sent|wparam|optional, 1 },
561     { WM_ERASEBKGND, sent|optional },
562     { WM_ACTIVATE, sent|wparam, 1 },
563     { WM_GETTEXT, 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     { 0 }
569 };
570 /* ShowWindow(SW_SHOWMINIMIZED) for a not visible overlapped window */
571 static const struct message WmShowMinOverlappedSeq[] = {
572     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
573     { HCBT_SETFOCUS, hook },
574     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
575     { WM_KILLFOCUS, sent },
576     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
577     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
578     { WM_GETTEXT, sent|optional },
579     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCOPYBITS|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
580     { WM_GETMINMAXINFO, sent|defwinproc },
581     { WM_NCCALCSIZE, sent|wparam, TRUE },
582     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
583     { WM_NCPAINT, sent|optional },
584     { WM_GETTEXT, sent|defwinproc|optional },
585     { WM_WINDOWPOSCHANGED, sent },
586     { WM_MOVE, sent|defwinproc },
587     { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
588     { WM_NCCALCSIZE, sent|optional },
589     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
590     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
591     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
592     { WM_NCACTIVATE, sent|wparam, 0 },
593     { WM_GETTEXT, sent|defwinproc|optional },
594     { WM_ACTIVATE, sent },
595     { WM_ACTIVATEAPP, sent|wparam, 0 },
596
597     /* Vista sometimes restores the window right away... */
598     { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
599     { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
600     { HCBT_MINMAX, hook|optional|lparam, 0, SW_RESTORE },
601     { WM_QUERYOPEN, sent|optional },
602     { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
603     { WM_GETMINMAXINFO, sent|optional|defwinproc },
604     { WM_NCCALCSIZE, sent|optional|wparam, TRUE },
605     { HCBT_ACTIVATE, hook|optional },
606     { WM_ACTIVATEAPP, sent|optional|wparam, 1 },
607     { WM_NCACTIVATE, sent|optional },
608     { WM_GETTEXT, sent|optional },
609     { WM_ACTIVATE, sent|optional|wparam, 1 },
610     { HCBT_SETFOCUS, hook|optional },
611     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
612     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
613     { WM_SETFOCUS, sent|optional },
614     { WM_NCPAINT, sent|optional },
615     { WM_GETTEXT, sent|defwinproc|optional },
616     { WM_ERASEBKGND, sent|optional },
617     { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
618     { WM_MOVE, sent|defwinproc|optional },
619     { WM_SIZE, sent|defwinproc|optional|wparam, SIZE_RESTORED },
620     { WM_ACTIVATE, sent|optional|wparam, 1 },
621     { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
622     { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
623
624     { WM_PAINT, sent|optional },
625     { WM_NCPAINT, sent|beginpaint|optional },
626     { WM_ERASEBKGND, sent|beginpaint|optional },
627     { 0 }
628 };
629 /* ShowWindow(SW_HIDE) for a visible overlapped window */
630 static const struct message WmHideOverlappedSeq[] = {
631     { WM_SHOWWINDOW, sent|wparam, 0 },
632     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
633     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
634     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
635     { WM_SIZE, sent|optional }, /* XP doesn't send it */
636     { WM_MOVE, sent|optional }, /* XP doesn't send it */
637     { WM_NCACTIVATE, sent|wparam|optional, 0 },
638     { WM_ACTIVATE, sent|wparam|optional, 0 },
639     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
640     { HCBT_SETFOCUS, hook|optional },
641     { WM_KILLFOCUS, sent|wparam, 0 },
642     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
643     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
644     { 0 }
645 };
646 /* DestroyWindow for a visible overlapped window */
647 static const struct message WmDestroyOverlappedSeq[] = {
648     { HCBT_DESTROYWND, hook },
649     { 0x0090, sent|optional },
650     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
651     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
652     { 0x0090, sent|optional },
653     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
654     { WM_NCACTIVATE, sent|optional|wparam, 0 },
655     { WM_ACTIVATE, sent|optional },
656     { WM_ACTIVATEAPP, sent|optional|wparam, 0 },
657     { WM_KILLFOCUS, sent|optional|wparam, 0 },
658     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
659     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
660     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
661     { WM_DESTROY, sent },
662     { WM_NCDESTROY, sent },
663     { 0 }
664 };
665 /* CreateWindow(WS_MAXIMIZE|WS_VISIBLE) for popup window */
666 static const struct message WmCreateMaxPopupSeq[] = {
667     { HCBT_CREATEWND, hook },
668     { WM_NCCREATE, sent },
669     { WM_NCCALCSIZE, sent|wparam, 0 },
670     { WM_CREATE, sent },
671     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
672     { WM_SIZE, sent|wparam, SIZE_RESTORED },
673     { WM_MOVE, sent },
674     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
675     { WM_GETMINMAXINFO, sent },
676     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
677     { WM_NCCALCSIZE, sent|wparam, TRUE },
678     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
679     { WM_MOVE, sent|defwinproc },
680     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
681     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
682     { WM_SHOWWINDOW, sent|wparam, 1 },
683     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
684     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
685     { HCBT_ACTIVATE, hook },
686     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
687     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
688     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
689     { WM_NCPAINT, sent|wparam|optional, 1 },
690     { WM_ERASEBKGND, sent|optional },
691     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_NOMOVE|SWP_NOSIZE },
692     { WM_ACTIVATEAPP, sent|wparam, 1 },
693     { WM_NCACTIVATE, sent },
694     { WM_ACTIVATE, sent|wparam, 1 },
695     { HCBT_SETFOCUS, hook },
696     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
697     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
698     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
699     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
700     { WM_GETTEXT, sent|optional },
701     { WM_SYNCPAINT, sent|wparam|optional, 4 },
702     { WM_NCPAINT, sent|wparam|optional, 1 },
703     { WM_ERASEBKGND, sent|optional },
704     { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
705     { WM_ERASEBKGND, sent|defwinproc|optional },
706     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
707     { 0 }
708 };
709 /* CreateWindow(WS_MAXIMIZE) for popup window, not initially visible */
710 static const struct message WmCreateInvisibleMaxPopupSeq[] = {
711     { HCBT_CREATEWND, hook },
712     { WM_NCCREATE, sent },
713     { WM_NCCALCSIZE, sent|wparam, 0 },
714     { WM_CREATE, sent },
715     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
716     { WM_SIZE, sent|wparam, SIZE_RESTORED },
717     { WM_MOVE, sent },
718     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
719     { WM_GETMINMAXINFO, sent },
720     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED  },
721     { WM_NCCALCSIZE, sent|wparam, TRUE },
722     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
723     { WM_MOVE, sent|defwinproc },
724     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
725     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
726     { 0 }
727 };
728 /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */
729 static const struct message WmShowMaxPopupResizedSeq[] = {
730     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
731     { WM_GETMINMAXINFO, sent },
732     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
733     { WM_NCCALCSIZE, sent|wparam, TRUE },
734     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
735     { HCBT_ACTIVATE, hook },
736     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
737     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
738     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
739     { WM_NCPAINT, sent|wparam|optional, 1 },
740     { WM_ERASEBKGND, sent|optional },
741     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
742     { WM_ACTIVATEAPP, sent|wparam, 1 },
743     { WM_NCACTIVATE, sent },
744     { WM_ACTIVATE, sent|wparam, 1 },
745     { HCBT_SETFOCUS, hook },
746     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
747     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
748     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
749     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
750     { WM_GETTEXT, sent|optional },
751     { WM_NCPAINT, sent|wparam|optional, 1 },
752     { WM_ERASEBKGND, sent|optional },
753     { WM_WINDOWPOSCHANGED, sent },
754     /* WinNT4.0 sends WM_MOVE */
755     { WM_MOVE, sent|defwinproc|optional },
756     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
757     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
758     { 0 }
759 };
760 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible popup window */
761 static const struct message WmShowMaxPopupSeq[] = {
762     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
763     { WM_GETMINMAXINFO, sent },
764     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
765     { WM_NCCALCSIZE, sent|wparam, TRUE },
766     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
767     { HCBT_ACTIVATE, hook },
768     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
769     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
770     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
771     { WM_ACTIVATEAPP, sent|wparam, 1 },
772     { WM_NCACTIVATE, sent },
773     { WM_ACTIVATE, sent|wparam, 1 },
774     { HCBT_SETFOCUS, hook },
775     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
776     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
777     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
778     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
779     { WM_GETTEXT, sent|optional },
780     { WM_SYNCPAINT, sent|wparam|optional, 4 },
781     { WM_NCPAINT, sent|wparam|optional, 1 },
782     { WM_ERASEBKGND, sent|optional },
783     { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
784     { WM_ERASEBKGND, sent|defwinproc|optional },
785     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE },
786     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
787     { 0 }
788 };
789 /* CreateWindow(WS_VISIBLE) for popup window */
790 static const struct message WmCreatePopupSeq[] = {
791     { HCBT_CREATEWND, hook },
792     { WM_NCCREATE, sent },
793     { WM_NCCALCSIZE, sent|wparam, 0 },
794     { WM_CREATE, sent },
795     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
796     { WM_SIZE, sent|wparam, SIZE_RESTORED },
797     { WM_MOVE, sent },
798     { WM_SHOWWINDOW, sent|wparam, 1 },
799     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
800     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
801     { HCBT_ACTIVATE, hook },
802     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
803     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
804     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
805     { WM_NCPAINT, sent|wparam|optional, 1 },
806     { WM_ERASEBKGND, sent|optional },
807     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
808     { WM_ACTIVATEAPP, sent|wparam, 1 },
809     { WM_NCACTIVATE, sent },
810     { WM_ACTIVATE, sent|wparam, 1 },
811     { HCBT_SETFOCUS, hook },
812     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
813     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
814     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
815     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
816     { WM_GETTEXT, sent|optional },
817     { WM_SYNCPAINT, sent|wparam|optional, 4 },
818     { WM_NCPAINT, sent|wparam|optional, 1 },
819     { WM_ERASEBKGND, sent|optional },
820     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
821     { 0 }
822 };
823 /* ShowWindow(SW_SHOWMAXIMIZED) for a visible popup window */
824 static const struct message WmShowVisMaxPopupSeq[] = {
825     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
826     { WM_GETMINMAXINFO, sent },
827     { WM_GETTEXT, sent|optional },
828     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
829     { WM_GETTEXT, sent|optional },
830     { WM_NCCALCSIZE, sent|wparam, TRUE },
831     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
832     { WM_NCPAINT, sent|wparam|optional, 1 },
833     { WM_ERASEBKGND, sent|optional },
834     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
835     { WM_MOVE, sent|defwinproc },
836     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
837     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
838     { 0 }
839 };
840 /* CreateWindow (for a child popup window, not initially visible) */
841 static const struct message WmCreateChildPopupSeq[] = {
842     { HCBT_CREATEWND, hook },
843     { WM_NCCREATE, sent }, 
844     { WM_NCCALCSIZE, sent|wparam, 0 },
845     { WM_CREATE, sent },
846     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
847     { WM_SIZE, sent|wparam, SIZE_RESTORED },
848     { WM_MOVE, sent },
849     { 0 }
850 };
851 /* CreateWindow (for a popup window, not initially visible,
852  * which sets WS_VISIBLE in WM_CREATE handler)
853  */
854 static const struct message WmCreateInvisiblePopupSeq[] = {
855     { HCBT_CREATEWND, hook },
856     { WM_NCCREATE, sent }, 
857     { WM_NCCALCSIZE, sent|wparam, 0 },
858     { WM_CREATE, sent },
859     { WM_STYLECHANGING, sent },
860     { WM_STYLECHANGED, sent },
861     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
862     { WM_SIZE, sent|wparam, SIZE_RESTORED },
863     { WM_MOVE, sent },
864     { 0 }
865 };
866 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
867  * for a popup window with WS_VISIBLE style set
868  */
869 static const struct message WmShowVisiblePopupSeq_2[] = {
870     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
871     { 0 }
872 };
873 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
874  * for a popup window with WS_VISIBLE style set
875  */
876 static const struct message WmShowVisiblePopupSeq_3[] = {
877     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
878     { HCBT_ACTIVATE, hook },
879     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
880     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
881     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
882     { WM_NCACTIVATE, sent },
883     { WM_ACTIVATE, sent|wparam, 1 },
884     { HCBT_SETFOCUS, hook },
885     { WM_KILLFOCUS, sent|parent },
886     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
887     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
888     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
889     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
890     { WM_SETFOCUS, sent|defwinproc },
891     { WM_GETTEXT, sent|optional },
892     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_SHOWWINDOW },
893     { 0 }
894 };
895 /* CreateWindow (for child window, not initially visible) */
896 static const struct message WmCreateChildSeq[] = {
897     { HCBT_CREATEWND, hook },
898     { WM_NCCREATE, sent }, 
899     /* child is inserted into parent's child list after WM_NCCREATE returns */
900     { WM_NCCALCSIZE, sent|wparam, 0 },
901     { WM_CREATE, sent },
902     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
903     { WM_SIZE, sent|wparam, SIZE_RESTORED },
904     { WM_MOVE, sent },
905     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
906     { 0 }
907 };
908 /* CreateWindow (for maximized child window, not initially visible) */
909 static const struct message WmCreateMaximizedChildSeq[] = {
910     { HCBT_CREATEWND, hook },
911     { WM_NCCREATE, sent }, 
912     { WM_NCCALCSIZE, sent|wparam, 0 },
913     { WM_CREATE, sent },
914     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
915     { WM_SIZE, sent|wparam, SIZE_RESTORED },
916     { WM_MOVE, sent },
917     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
918     { WM_GETMINMAXINFO, sent },
919     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
920     { WM_NCCALCSIZE, sent|wparam, 1 },
921     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
922     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
923     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
924     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
925     { 0 }
926 };
927 /* CreateWindow (for a child window, initially visible) */
928 static const struct message WmCreateVisibleChildSeq[] = {
929     { HCBT_CREATEWND, hook },
930     { WM_NCCREATE, sent }, 
931     /* child is inserted into parent's child list after WM_NCCREATE returns */
932     { WM_NCCALCSIZE, sent|wparam, 0 },
933     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
934     { WM_CREATE, sent },
935     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
936     { WM_SIZE, sent|wparam, SIZE_RESTORED },
937     { WM_MOVE, sent },
938     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
939     { WM_SHOWWINDOW, sent|wparam, 1 },
940     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
941     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
942     { WM_ERASEBKGND, sent|parent|optional },
943     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
944     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */
945     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
946     { 0 }
947 };
948 /* ShowWindow(SW_SHOW) for a not visible child window */
949 static const struct message WmShowChildSeq[] = {
950     { WM_SHOWWINDOW, sent|wparam, 1 },
951     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
952     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
953     { WM_ERASEBKGND, sent|parent|optional },
954     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
955     { 0 }
956 };
957 /* ShowWindow(SW_HIDE) for a visible child window */
958 static const struct message WmHideChildSeq[] = {
959     { WM_SHOWWINDOW, sent|wparam, 0 },
960     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
961     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
962     { WM_ERASEBKGND, sent|parent|optional },
963     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
964     { 0 }
965 };
966 /* ShowWindow(SW_HIDE) for a visible child window checking all parent events*/
967 static const struct message WmHideChildSeq2[] = {
968     { WM_SHOWWINDOW, sent|wparam, 0 },
969     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
970     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
971     { WM_ERASEBKGND, sent|parent|optional },
972     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
973     { 0 }
974 };
975 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
976  * for a not visible child window
977  */
978 static const struct message WmShowChildSeq_2[] = {
979     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
980     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
981     { WM_CHILDACTIVATE, sent },
982     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
983     { 0 }
984 };
985 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
986  * for a not visible child window
987  */
988 static const struct message WmShowChildSeq_3[] = {
989     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
990     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
991     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
992     { 0 }
993 };
994 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
995  * for a visible child window with a caption
996  */
997 static const struct message WmShowChildSeq_4[] = {
998     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
999     { WM_CHILDACTIVATE, sent },
1000     { 0 }
1001 };
1002 /* ShowWindow(SW_MINIMIZE) for child with invisible parent */
1003 static const struct message WmShowChildInvisibleParentSeq_1[] = {
1004     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1005     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1006     { WM_NCCALCSIZE, sent|wparam, 1 },
1007     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1008     { WM_CHILDACTIVATE, sent|optional },
1009     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1010     { WM_MOVE, sent|defwinproc },
1011     { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1012     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1013     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1014     /* FIXME: Wine creates an icon/title window while Windows doesn't */
1015     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1016     { WM_GETTEXT, sent|optional },
1017     { 0 }
1018 };
1019 /* repeated ShowWindow(SW_MINIMIZE) for child with invisible parent */
1020 static const struct message WmShowChildInvisibleParentSeq_1r[] = {
1021     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1022     { 0 }
1023 };
1024 /* ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1025 static const struct message WmShowChildInvisibleParentSeq_2[] = {
1026     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1027     { WM_GETMINMAXINFO, sent },
1028     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
1029     { WM_NCCALCSIZE, sent|wparam, 1 },
1030     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1031     { WM_CHILDACTIVATE, sent },
1032     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1033     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1034     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1035     { 0 }
1036 };
1037 /* repeated ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1038 static const struct message WmShowChildInvisibleParentSeq_2r[] = {
1039     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1040     { 0 }
1041 };
1042 /* ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1043 static const struct message WmShowChildInvisibleParentSeq_3[] = {
1044     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1045     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1046     { WM_NCCALCSIZE, sent|wparam, 1 },
1047     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1048     { WM_CHILDACTIVATE, sent },
1049     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1050     { WM_MOVE, sent|defwinproc },
1051     { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1052     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1053     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1054     /* FIXME: Wine creates an icon/title window while Windows doesn't */
1055     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1056     { WM_GETTEXT, sent|optional },
1057     { 0 }
1058 };
1059 /* repeated ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1060 static const struct message WmShowChildInvisibleParentSeq_3r[] = {
1061     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1062     { 0 }
1063 };
1064 /* ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1065 static const struct message WmShowChildInvisibleParentSeq_4[] = {
1066     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1067     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
1068     { WM_NCCALCSIZE, sent|wparam, 1 },
1069     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1070     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1071     { WM_MOVE, sent|defwinproc },
1072     { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1073     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1074     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1075     /* FIXME: Wine creates an icon/title window while Windows doesn't */
1076     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1077     { WM_GETTEXT, sent|optional },
1078     { 0 }
1079 };
1080 /* repeated ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1081 static const struct message WmShowChildInvisibleParentSeq_4r[] = {
1082     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1083     { 0 }
1084 };
1085 /* ShowWindow(SW_SHOW) for child with invisible parent */
1086 static const struct message WmShowChildInvisibleParentSeq_5[] = {
1087     { WM_SHOWWINDOW, sent|wparam, 1 },
1088     { 0 }
1089 };
1090 /* ShowWindow(SW_HIDE) for child with invisible parent */
1091 static const struct message WmHideChildInvisibleParentSeq[] = {
1092     { WM_SHOWWINDOW, sent|wparam, 0 },
1093     { 0 }
1094 };
1095 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
1096 static const struct message WmShowChildInvisibleParentSeq_6[] = {
1097     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1098     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1099     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1100     { 0 }
1101 };
1102 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
1103 static const struct message WmHideChildInvisibleParentSeq_2[] = {
1104     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1105     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1106     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1107     { 0 }
1108 };
1109 /* DestroyWindow for a visible child window */
1110 static const struct message WmDestroyChildSeq[] = {
1111     { HCBT_DESTROYWND, hook },
1112     { 0x0090, sent|optional },
1113     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1114     { WM_SHOWWINDOW, sent|wparam, 0 },
1115     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1116     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1117     { WM_ERASEBKGND, sent|parent|optional },
1118     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1119     { HCBT_SETFOCUS, hook }, /* set focus to a parent */
1120     { WM_KILLFOCUS, sent },
1121     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1122     { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
1123     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1124     { WM_SETFOCUS, sent|parent },
1125     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1126     { WM_DESTROY, sent },
1127     { WM_DESTROY, sent|optional }, /* some other (IME?) window */
1128     { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
1129     { WM_NCDESTROY, sent },
1130     { 0 }
1131 };
1132 /* visible child window destroyed by thread exit */
1133 static const struct message WmExitThreadSeq[] = {
1134     { WM_NCDESTROY, sent },  /* actually in grandchild */
1135     { WM_PAINT, sent|parent },
1136     { WM_ERASEBKGND, sent|parent|beginpaint },
1137     { 0 }
1138 };
1139 /* DestroyWindow for a visible child window with invisible parent */
1140 static const struct message WmDestroyInvisibleChildSeq[] = {
1141     { HCBT_DESTROYWND, hook },
1142     { 0x0090, sent|optional },
1143     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1144     { WM_SHOWWINDOW, sent|wparam, 0 },
1145     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1146     { WM_DESTROY, sent },
1147     { WM_NCDESTROY, sent },
1148     { 0 }
1149 };
1150 /* Moving the mouse in nonclient area */
1151 static const struct message WmMouseMoveInNonClientAreaSeq[] = { /* FIXME: add */
1152     { WM_NCHITTEST, sent },
1153     { WM_SETCURSOR, sent },
1154     { WM_NCMOUSEMOVE, posted },
1155     { 0 }
1156 };
1157 /* Moving the mouse in client area */
1158 static const struct message WmMouseMoveInClientAreaSeq[] = { /* FIXME: add */
1159     { WM_NCHITTEST, sent },
1160     { WM_SETCURSOR, sent },
1161     { WM_MOUSEMOVE, posted },
1162     { 0 }
1163 };
1164 /* Moving by dragging the title bar (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
1165 static const struct message WmDragTitleBarSeq[] = { /* FIXME: add */
1166     { WM_NCLBUTTONDOWN, sent|wparam, HTCAPTION },
1167     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_MOVE+2 },
1168     { WM_GETMINMAXINFO, sent|defwinproc },
1169     { WM_ENTERSIZEMOVE, sent|defwinproc },
1170     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
1171     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
1172     { WM_MOVE, sent|defwinproc },
1173     { WM_EXITSIZEMOVE, sent|defwinproc },
1174     { 0 }
1175 };
1176 /* Sizing by dragging the thick borders (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
1177 static const struct message WmDragThickBordersBarSeq[] = { /* FIXME: add */
1178     { WM_NCLBUTTONDOWN, sent|wparam, 0xd },
1179     { WM_SYSCOMMAND, sent|defwinproc|wparam, 0xf004 },
1180     { WM_GETMINMAXINFO, sent|defwinproc },
1181     { WM_ENTERSIZEMOVE, sent|defwinproc },
1182     { WM_SIZING, sent|defwinproc|wparam, 4}, /* one for each mouse movement */
1183     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
1184     { WM_GETMINMAXINFO, sent|defwinproc },
1185     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
1186     { WM_NCPAINT, sent|defwinproc|wparam, 1 },
1187     { WM_GETTEXT, sent|defwinproc },
1188     { WM_ERASEBKGND, sent|defwinproc },
1189     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
1190     { WM_MOVE, sent|defwinproc },
1191     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1192     { WM_EXITSIZEMOVE, sent|defwinproc },
1193     { 0 }
1194 };
1195 /* Resizing child window with MoveWindow (32) */
1196 static const struct message WmResizingChildWithMoveWindowSeq[] = {
1197     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
1198     { WM_NCCALCSIZE, sent|wparam, 1 },
1199     { WM_ERASEBKGND, sent|parent|optional },
1200     { WM_ERASEBKGND, sent|optional },
1201     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE },
1202     { WM_MOVE, sent|defwinproc },
1203     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1204     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1205     { 0 }
1206 };
1207 /* Clicking on inactive button */
1208 static const struct message WmClickInactiveButtonSeq[] = { /* FIXME: add */
1209     { WM_NCHITTEST, sent },
1210     { WM_PARENTNOTIFY, sent|parent|wparam, WM_LBUTTONDOWN },
1211     { WM_MOUSEACTIVATE, sent },
1212     { WM_MOUSEACTIVATE, sent|parent|defwinproc },
1213     { WM_SETCURSOR, sent },
1214     { WM_SETCURSOR, sent|parent|defwinproc },
1215     { WM_LBUTTONDOWN, posted },
1216     { WM_KILLFOCUS, posted|parent },
1217     { WM_SETFOCUS, posted },
1218     { WM_CTLCOLORBTN, posted|parent },
1219     { BM_SETSTATE, posted },
1220     { WM_CTLCOLORBTN, posted|parent },
1221     { WM_LBUTTONUP, posted },
1222     { BM_SETSTATE, posted },
1223     { WM_CTLCOLORBTN, posted|parent },
1224     { WM_COMMAND, posted|parent },
1225     { 0 }
1226 };
1227 /* Reparenting a button (16/32) */
1228 /* The last child (button) reparented gets topmost for its new parent. */
1229 static const struct message WmReparentButtonSeq[] = { /* FIXME: add */
1230     { WM_SHOWWINDOW, sent|wparam, 0 },
1231     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1232     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1233     { WM_ERASEBKGND, sent|parent },
1234     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1235     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
1236     { WM_CHILDACTIVATE, sent },
1237     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW },
1238     { WM_MOVE, sent|defwinproc },
1239     { WM_SHOWWINDOW, sent|wparam, 1 },
1240     { 0 }
1241 };
1242 /* Creation of a custom dialog (32) */
1243 static const struct message WmCreateCustomDialogSeq[] = {
1244     { HCBT_CREATEWND, hook },
1245     { WM_GETMINMAXINFO, sent },
1246     { WM_NCCREATE, sent },
1247     { WM_NCCALCSIZE, sent|wparam, 0 },
1248     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1249     { WM_CREATE, sent },
1250     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1251     { WM_NOTIFYFORMAT, sent|optional },
1252     { WM_QUERYUISTATE, sent|optional },
1253     { WM_WINDOWPOSCHANGING, sent|optional },
1254     { WM_GETMINMAXINFO, sent|optional },
1255     { WM_NCCALCSIZE, sent|optional },
1256     { WM_WINDOWPOSCHANGED, sent|optional },
1257     { WM_SHOWWINDOW, sent|wparam, 1 },
1258     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1259     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1260     { HCBT_ACTIVATE, hook },
1261     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1262
1263
1264     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1265
1266     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1267
1268     { WM_NCACTIVATE, sent },
1269     { WM_GETTEXT, sent|optional|defwinproc },
1270     { WM_GETTEXT, sent|optional|defwinproc },
1271     { WM_GETTEXT, sent|optional|defwinproc },
1272     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
1273     { WM_ACTIVATE, sent|wparam, 1 },
1274     { WM_GETTEXT, sent|optional },
1275     { WM_KILLFOCUS, sent|parent },
1276     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1277     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1278     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1279     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1280     { WM_SETFOCUS, sent },
1281     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1282     { WM_NCPAINT, sent|wparam, 1 },
1283     { WM_GETTEXT, sent|optional|defwinproc },
1284     { WM_GETTEXT, sent|optional|defwinproc },
1285     { WM_ERASEBKGND, sent },
1286     { WM_CTLCOLORDLG, sent|optional|defwinproc },
1287     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1288     { WM_GETTEXT, sent|optional },
1289     { WM_GETTEXT, sent|optional },
1290     { WM_NCCALCSIZE, sent|optional },
1291     { WM_NCPAINT, sent|optional },
1292     { WM_GETTEXT, sent|optional|defwinproc },
1293     { WM_GETTEXT, sent|optional|defwinproc },
1294     { WM_ERASEBKGND, sent|optional },
1295     { WM_CTLCOLORDLG, sent|optional|defwinproc },
1296     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1297     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1298     { WM_MOVE, sent },
1299     { 0 }
1300 };
1301 /* Calling EndDialog for a custom dialog (32) */
1302 static const struct message WmEndCustomDialogSeq[] = {
1303     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1304     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1305     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1306     { WM_GETTEXT, sent|optional },
1307     { HCBT_ACTIVATE, hook },
1308     { WM_NCACTIVATE, sent|wparam, 0 },
1309     { WM_GETTEXT, sent|optional|defwinproc },
1310     { WM_GETTEXT, sent|optional|defwinproc },
1311     { WM_ACTIVATE, sent|wparam, 0 },
1312     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1313     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1314     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1315     { WM_GETTEXT, sent|optional|defwinproc },
1316     { WM_GETTEXT, sent|optional|defwinproc },
1317     { HCBT_SETFOCUS, hook },
1318     { WM_KILLFOCUS, sent },
1319     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1320     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1321     { WM_IME_NOTIFY, sent|wparam|optional, 1 },
1322     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1323     { WM_SETFOCUS, sent|parent|defwinproc },
1324     { 0 }
1325 };
1326 /* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
1327 static const struct message WmShowCustomDialogSeq[] = {
1328     { WM_SHOWWINDOW, sent|wparam, 1 },
1329     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1330     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1331     { HCBT_ACTIVATE, hook },
1332     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1333
1334     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1335
1336     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1337     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
1338     { WM_NCACTIVATE, sent },
1339     { WM_ACTIVATE, sent|wparam, 1 },
1340     { WM_GETTEXT, sent|optional },
1341
1342     { WM_KILLFOCUS, sent|parent },
1343     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1344     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1345     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1346     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1347     { WM_SETFOCUS, sent },
1348     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1349     { WM_NCPAINT, sent|wparam, 1 },
1350     { WM_ERASEBKGND, sent },
1351     { WM_CTLCOLORDLG, sent|defwinproc },
1352     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1353     { 0 }
1354 };
1355 /* Creation and destruction of a modal dialog (32) */
1356 static const struct message WmModalDialogSeq[] = {
1357     { WM_CANCELMODE, sent|parent },
1358     { HCBT_SETFOCUS, hook },
1359     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1360     { WM_KILLFOCUS, sent|parent },
1361     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1362     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1363     { WM_ENABLE, sent|parent|wparam, 0 },
1364     { HCBT_CREATEWND, hook },
1365     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1366     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1367     { WM_SETFONT, sent },
1368     { WM_INITDIALOG, sent },
1369     { WM_CHANGEUISTATE, sent|optional },
1370     { WM_UPDATEUISTATE, sent|optional },
1371     { WM_SHOWWINDOW, sent },
1372     { HCBT_ACTIVATE, hook },
1373     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1374     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1375     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1376     { WM_NCACTIVATE, sent },
1377     { WM_GETTEXT, sent|optional },
1378     { WM_ACTIVATE, sent|wparam, 1 },
1379     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1380     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1381     { WM_NCPAINT, sent|optional },
1382     { WM_GETTEXT, sent|optional },
1383     { WM_ERASEBKGND, sent|optional },
1384     { WM_CTLCOLORDLG, sent|optional },
1385     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1386     { WM_GETTEXT, sent|optional },
1387     { WM_NCCALCSIZE, sent|optional },
1388     { WM_NCPAINT, sent|optional },
1389     { WM_GETTEXT, sent|optional },
1390     { WM_ERASEBKGND, sent|optional },
1391     { WM_CTLCOLORDLG, sent|optional },
1392     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1393     { WM_PAINT, sent|optional },
1394     { WM_CTLCOLORBTN, sent|optional },
1395     { WM_GETTITLEBARINFOEX, sent|optional },
1396     { WM_ENTERIDLE, sent|parent|optional },
1397     { WM_ENTERIDLE, sent|parent|optional },
1398     { WM_ENTERIDLE, sent|parent|optional },
1399     { WM_ENTERIDLE, sent|parent|optional },
1400     { WM_ENTERIDLE, sent|parent|optional },
1401     { WM_ENTERIDLE, sent|parent|optional },
1402     { WM_ENTERIDLE, sent|parent|optional },
1403     { WM_ENTERIDLE, sent|parent|optional },
1404     { WM_ENTERIDLE, sent|parent|optional },
1405     { WM_ENTERIDLE, sent|parent|optional },
1406     { WM_ENTERIDLE, sent|parent|optional },
1407     { WM_ENTERIDLE, sent|parent|optional },
1408     { WM_ENTERIDLE, sent|parent|optional },
1409     { WM_ENTERIDLE, sent|parent|optional },
1410     { WM_ENTERIDLE, sent|parent|optional },
1411     { WM_ENTERIDLE, sent|parent|optional },
1412     { WM_ENTERIDLE, sent|parent|optional },
1413     { WM_ENTERIDLE, sent|parent|optional },
1414     { WM_ENTERIDLE, sent|parent|optional },
1415     { WM_ENTERIDLE, sent|parent|optional },
1416     { WM_TIMER, sent },
1417     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1418     { WM_ENABLE, sent|parent|wparam, 1 },
1419     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1420     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1421     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1422     { WM_GETTEXT, sent|optional },
1423     { HCBT_ACTIVATE, hook },
1424     { WM_NCACTIVATE, sent|wparam, 0 },
1425     { WM_GETTEXT, sent|optional },
1426     { WM_ACTIVATE, sent|wparam, 0 },
1427     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1428     { WM_WINDOWPOSCHANGING, sent|optional },
1429     { WM_WINDOWPOSCHANGED, sent|optional },
1430     { HCBT_SETFOCUS, hook },
1431     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1432     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1433     { WM_SETFOCUS, sent|parent|defwinproc },
1434     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 },
1435     { HCBT_DESTROYWND, hook },
1436     { 0x0090, sent|optional },
1437     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1438     { WM_DESTROY, sent },
1439     { WM_NCDESTROY, sent },
1440     { 0 }
1441 };
1442 /* Creation of a modal dialog that is resized inside WM_INITDIALOG (32) */
1443 static const struct message WmCreateModalDialogResizeSeq[] = { /* FIXME: add */
1444     /* (inside dialog proc, handling WM_INITDIALOG) */
1445     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1446     { WM_NCCALCSIZE, sent },
1447     { WM_NCACTIVATE, sent|parent|wparam, 0 },
1448     { WM_GETTEXT, sent|defwinproc },
1449     { WM_ACTIVATE, sent|parent|wparam, 0 },
1450     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1451     { WM_WINDOWPOSCHANGING, sent|parent },
1452     { WM_NCACTIVATE, sent|wparam, 1 },
1453     { WM_ACTIVATE, sent|wparam, 1 },
1454     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1455     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1456     /* (setting focus) */
1457     { WM_SHOWWINDOW, sent|wparam, 1 },
1458     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1459     { WM_NCPAINT, sent },
1460     { WM_GETTEXT, sent|defwinproc },
1461     { WM_ERASEBKGND, sent },
1462     { WM_CTLCOLORDLG, sent|defwinproc },
1463     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1464     { WM_PAINT, sent },
1465     /* (bunch of WM_CTLCOLOR* for each control) */
1466     { WM_PAINT, sent|parent },
1467     { WM_ENTERIDLE, sent|parent|wparam, 0 },
1468     { WM_SETCURSOR, sent|parent },
1469     { 0 }
1470 };
1471 /* SetMenu for NonVisible windows with size change*/
1472 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
1473     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1474     { WM_NCCALCSIZE, sent|wparam, 1 },
1475     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1476     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
1477     { WM_MOVE, sent|defwinproc },
1478     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1479     { WM_NCCALCSIZE,sent|wparam|optional, 1 }, /* XP */
1480     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1481     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1482     { WM_GETTEXT, sent|optional },
1483     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1484     { 0 }
1485 };
1486 /* SetMenu for NonVisible windows with no size change */
1487 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
1488     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1489     { WM_NCCALCSIZE, sent|wparam, 1 },
1490     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1491     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1492     { 0 }
1493 };
1494 /* SetMenu for Visible windows with size change */
1495 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
1496     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1497     { WM_NCCALCSIZE, sent|wparam, 1 },
1498     { 0x0093, sent|defwinproc|optional },
1499     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1500     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1501     { 0x0093, sent|defwinproc|optional },
1502     { 0x0093, sent|defwinproc|optional },
1503     { 0x0091, sent|defwinproc|optional },
1504     { 0x0092, sent|defwinproc|optional },
1505     { WM_GETTEXT, sent|defwinproc|optional },
1506     { WM_ERASEBKGND, sent|optional },
1507     { WM_ACTIVATE, sent|optional },
1508     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1509     { WM_MOVE, sent|defwinproc },
1510     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1511     { 0x0093, sent|optional },
1512     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1513     { 0x0093, sent|defwinproc|optional },
1514     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1515     { 0x0093, sent|defwinproc|optional },
1516     { 0x0093, sent|defwinproc|optional },
1517     { 0x0091, sent|defwinproc|optional },
1518     { 0x0092, sent|defwinproc|optional },
1519     { WM_ERASEBKGND, sent|optional },
1520     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1521     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1522     { 0 }
1523 };
1524 /* SetMenu for Visible windows with no size change */
1525 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
1526     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1527     { WM_NCCALCSIZE, sent|wparam, 1 },
1528     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1529     { WM_GETTEXT, sent|defwinproc|optional },
1530     { WM_ERASEBKGND, sent|optional },
1531     { WM_ACTIVATE, sent|optional },
1532     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1533     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1534     { 0 }
1535 };
1536 /* DrawMenuBar for a visible window */
1537 static const struct message WmDrawMenuBarSeq[] =
1538 {
1539     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1540     { WM_NCCALCSIZE, sent|wparam, 1 },
1541     { 0x0093, sent|defwinproc|optional },
1542     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1543     { 0x0093, sent|defwinproc|optional },
1544     { 0x0093, sent|defwinproc|optional },
1545     { 0x0091, sent|defwinproc|optional },
1546     { 0x0092, sent|defwinproc|optional },
1547     { WM_GETTEXT, sent|defwinproc|optional },
1548     { WM_ERASEBKGND, sent|optional },
1549     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1550     { 0x0093, sent|optional },
1551     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1552     { 0 }
1553 };
1554
1555 static const struct message WmSetRedrawFalseSeq[] =
1556 {
1557     { WM_SETREDRAW, sent|wparam, 0 },
1558     { 0 }
1559 };
1560
1561 static const struct message WmSetRedrawTrueSeq[] =
1562 {
1563     { WM_SETREDRAW, sent|wparam, 1 },
1564     { 0 }
1565 };
1566
1567 static const struct message WmEnableWindowSeq_1[] =
1568 {
1569     { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1570     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1571     { HCBT_SETFOCUS, hook|optional },
1572     { WM_KILLFOCUS, sent|optional },
1573     { WM_ENABLE, sent|wparam|lparam, FALSE, 0 },
1574     { 0 }
1575 };
1576
1577 static const struct message WmEnableWindowSeq_2[] =
1578 {
1579     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1580     { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
1581     { 0 }
1582 };
1583
1584 static const struct message WmGetScrollRangeSeq[] =
1585 {
1586     { SBM_GETRANGE, sent },
1587     { 0 }
1588 };
1589 static const struct message WmGetScrollInfoSeq[] =
1590 {
1591     { SBM_GETSCROLLINFO, sent },
1592     { 0 }
1593 };
1594 static const struct message WmSetScrollRangeSeq[] =
1595 {
1596     /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
1597        sends SBM_SETSCROLLINFO.
1598      */
1599     { SBM_SETSCROLLINFO, sent },
1600     { 0 }
1601 };
1602 /* SetScrollRange for a window without a non-client area */
1603 static const struct message WmSetScrollRangeHSeq_empty[] =
1604 {
1605     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_HSCROLL, 0 },
1606     { 0 }
1607 };
1608 static const struct message WmSetScrollRangeVSeq_empty[] =
1609 {
1610     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_VSCROLL, 0 },
1611     { 0 }
1612 };
1613 static const struct message WmSetScrollRangeHVSeq[] =
1614 {
1615     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1616     { WM_NCCALCSIZE, sent|wparam, 1 },
1617     { WM_GETTEXT, sent|defwinproc|optional },
1618     { WM_ERASEBKGND, sent|optional },
1619     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1620     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1621     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1622     { 0 }
1623 };
1624 /* SetScrollRange for a window with a non-client area */
1625 static const struct message WmSetScrollRangeHV_NC_Seq[] =
1626 {
1627     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1628     { WM_NCCALCSIZE, sent|wparam, 1 },
1629     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1630     { WM_NCPAINT, sent|optional },
1631     { WM_STYLECHANGING, sent|defwinproc|optional },
1632     { WM_STYLECHANGED, sent|defwinproc|optional },
1633     { WM_STYLECHANGING, sent|defwinproc|optional },
1634     { WM_STYLECHANGED, sent|defwinproc|optional },
1635     { WM_STYLECHANGING, sent|defwinproc|optional },
1636     { WM_STYLECHANGED, sent|defwinproc|optional },
1637     { WM_STYLECHANGING, sent|defwinproc|optional },
1638     { WM_STYLECHANGED, sent|defwinproc|optional },
1639     { WM_GETTEXT, sent|defwinproc|optional },
1640     { WM_GETTEXT, sent|defwinproc|optional },
1641     { WM_ERASEBKGND, sent|optional },
1642     { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
1643     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOCLIENTSIZE },
1644     { WM_SIZE, sent|defwinproc|optional },
1645     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1646     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1647     { WM_GETTEXT, sent|optional },
1648     { WM_GETTEXT, sent|optional },
1649     { WM_GETTEXT, sent|optional },
1650     { WM_GETTEXT, sent|optional },
1651     { 0 }
1652 };
1653 /* test if we receive the right sequence of messages */
1654 /* after calling ShowWindow( SW_SHOWNA) */
1655 static const struct message WmSHOWNAChildInvisParInvis[] = {
1656     { WM_SHOWWINDOW, sent|wparam, 1 },
1657     { 0 }
1658 };
1659 static const struct message WmSHOWNAChildVisParInvis[] = {
1660     { WM_SHOWWINDOW, sent|wparam, 1 },
1661     { 0 }
1662 };
1663 static const struct message WmSHOWNAChildVisParVis[] = {
1664     { WM_SHOWWINDOW, sent|wparam, 1 },
1665     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1666     { 0 }
1667 };
1668 static const struct message WmSHOWNAChildInvisParVis[] = {
1669     { WM_SHOWWINDOW, sent|wparam, 1 },
1670     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1671     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1672     { WM_ERASEBKGND, sent|optional },
1673     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOCLIENTMOVE },
1674     { 0 }
1675 };
1676 static const struct message WmSHOWNATopVisible[] = {
1677     { WM_SHOWWINDOW, sent|wparam, 1 },
1678     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1679     { WM_NCPAINT, sent|wparam|optional, 1 },
1680     { WM_GETTEXT, sent|defwinproc|optional },
1681     { WM_ERASEBKGND, sent|optional },
1682     { WM_WINDOWPOSCHANGED, sent|optional },
1683     { 0 }
1684 };
1685 static const struct message WmSHOWNATopInvisible[] = {
1686     { WM_NOTIFYFORMAT, sent|optional },
1687     { WM_QUERYUISTATE, sent|optional },
1688     { WM_WINDOWPOSCHANGING, sent|optional },
1689     { WM_GETMINMAXINFO, sent|optional },
1690     { WM_NCCALCSIZE, sent|optional },
1691     { WM_WINDOWPOSCHANGED, sent|optional },
1692     { WM_SHOWWINDOW, sent|wparam, 1 },
1693     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1694     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1695     { WM_NCPAINT, sent|wparam|optional, 1 },
1696     { WM_GETTEXT, sent|defwinproc|optional },
1697     { WM_ERASEBKGND, sent|optional },
1698     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1699     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1700     { WM_NCPAINT, sent|wparam|optional, 1 },
1701     { WM_ERASEBKGND, sent|optional },
1702     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1703     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1704     { WM_MOVE, sent },
1705     { 0 }
1706 };
1707
1708 static int after_end_dialog, test_def_id;
1709 static int sequence_cnt, sequence_size;
1710 static struct recvd_message* sequence;
1711 static int log_all_parent_messages;
1712 static int paint_loop_done;
1713
1714 /* user32 functions */
1715 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
1716 static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO);
1717 static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG);
1718 static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO);
1719 static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD);
1720 static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*);
1721 static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
1722 static BOOL (WINAPI *pGetMonitorInfoA)(HMONITOR,LPMONITORINFO);
1723 static HMONITOR (WINAPI *pMonitorFromPoint)(POINT,DWORD);
1724 static BOOL (WINAPI *pUpdateLayeredWindow)(HWND,HDC,POINT*,SIZE*,HDC,POINT*,COLORREF,BLENDFUNCTION*,DWORD);
1725 /* kernel32 functions */
1726 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
1727
1728 static void init_procs(void)
1729 {
1730     HMODULE user32 = GetModuleHandleA("user32.dll");
1731     HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
1732
1733 #define GET_PROC(dll, func) \
1734     p ## func = (void*)GetProcAddress(dll, #func); \
1735     if(!p ## func) { \
1736       trace("GetProcAddress(%s) failed\n", #func); \
1737     }
1738
1739     GET_PROC(user32, GetAncestor)
1740     GET_PROC(user32, GetMenuInfo)
1741     GET_PROC(user32, NotifyWinEvent)
1742     GET_PROC(user32, SetMenuInfo)
1743     GET_PROC(user32, SetWinEventHook)
1744     GET_PROC(user32, TrackMouseEvent)
1745     GET_PROC(user32, UnhookWinEvent)
1746     GET_PROC(user32, GetMonitorInfoA)
1747     GET_PROC(user32, MonitorFromPoint)
1748     GET_PROC(user32, UpdateLayeredWindow)
1749
1750     GET_PROC(kernel32, GetCPInfoExA)
1751
1752 #undef GET_PROC
1753 }
1754
1755 static const char *get_winpos_flags(UINT flags)
1756 {
1757     static char buffer[300];
1758
1759     buffer[0] = 0;
1760 #define DUMP(flag) do { if (flags & flag) { strcat( buffer, "|" #flag ); flags &= ~flag; } } while(0)
1761     DUMP( SWP_SHOWWINDOW );
1762     DUMP( SWP_HIDEWINDOW );
1763     DUMP( SWP_NOACTIVATE );
1764     DUMP( SWP_FRAMECHANGED );
1765     DUMP( SWP_NOCOPYBITS );
1766     DUMP( SWP_NOOWNERZORDER );
1767     DUMP( SWP_NOSENDCHANGING );
1768     DUMP( SWP_DEFERERASE );
1769     DUMP( SWP_ASYNCWINDOWPOS );
1770     DUMP( SWP_NOZORDER );
1771     DUMP( SWP_NOREDRAW );
1772     DUMP( SWP_NOSIZE );
1773     DUMP( SWP_NOMOVE );
1774     DUMP( SWP_NOCLIENTSIZE );
1775     DUMP( SWP_NOCLIENTMOVE );
1776     if (flags) sprintf(buffer + strlen(buffer),"|0x%04x", flags);
1777     return buffer + 1;
1778 #undef DUMP
1779 }
1780
1781 static BOOL ignore_message( UINT message )
1782 {
1783     /* these are always ignored */
1784     return (message >= 0xc000 ||
1785             message == WM_GETICON ||
1786             message == WM_GETOBJECT ||
1787             message == WM_TIMECHANGE ||
1788             message == WM_DISPLAYCHANGE ||
1789             message == WM_DEVICECHANGE ||
1790             message == WM_DWMNCRENDERINGCHANGED);
1791 }
1792
1793
1794 #define add_message(msg) add_message_(__LINE__,msg);
1795 static void add_message_(int line, const struct recvd_message *msg)
1796 {
1797     struct recvd_message *seq;
1798
1799     if (!sequence) 
1800     {
1801         sequence_size = 10;
1802         sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof(*sequence) );
1803     }
1804     if (sequence_cnt == sequence_size) 
1805     {
1806         sequence_size *= 2;
1807         sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof(*sequence) );
1808     }
1809     assert(sequence);
1810
1811     seq = &sequence[sequence_cnt];
1812     seq->hwnd = msg->hwnd;
1813     seq->message = msg->message;
1814     seq->flags = msg->flags;
1815     seq->wParam = msg->wParam;
1816     seq->lParam = msg->lParam;
1817     seq->line   = line;
1818     seq->descr  = msg->descr;
1819     seq->output[0] = 0;
1820
1821     if (msg->descr)
1822     {
1823         if (msg->flags & hook)
1824         {
1825             static const char * const CBT_code_name[10] =
1826             {
1827                 "HCBT_MOVESIZE",
1828                 "HCBT_MINMAX",
1829                 "HCBT_QS",
1830                 "HCBT_CREATEWND",
1831                 "HCBT_DESTROYWND",
1832                 "HCBT_ACTIVATE",
1833                 "HCBT_CLICKSKIPPED",
1834                 "HCBT_KEYSKIPPED",
1835                 "HCBT_SYSCOMMAND",
1836                 "HCBT_SETFOCUS"
1837             };
1838             const char *code_name = (msg->message <= HCBT_SETFOCUS) ? CBT_code_name[msg->message] : "Unknown";
1839
1840             sprintf( seq->output, "%s: hook %d (%s) wp %08lx lp %08lx",
1841                      msg->descr, msg->message, code_name, msg->wParam, msg->lParam );
1842         }
1843         else if (msg->flags & winevent_hook)
1844         {
1845             sprintf( seq->output, "%s: winevent %p %08x %08lx %08lx",
1846                      msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
1847         }
1848         else
1849         {
1850             switch (msg->message)
1851             {
1852             case WM_WINDOWPOSCHANGING:
1853             case WM_WINDOWPOSCHANGED:
1854             {
1855                 WINDOWPOS *winpos = (WINDOWPOS *)msg->lParam;
1856
1857                 sprintf( seq->output, "%s: %p WM_WINDOWPOS%s wp %08lx lp %08lx after %p x %d y %d cx %d cy %d flags %s",
1858                           msg->descr, msg->hwnd,
1859                           (msg->message == WM_WINDOWPOSCHANGING) ? "CHANGING" : "CHANGED",
1860                           msg->wParam, msg->lParam, winpos->hwndInsertAfter,
1861                           winpos->x, winpos->y, winpos->cx, winpos->cy,
1862                           get_winpos_flags(winpos->flags) );
1863
1864                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
1865                  * in the high word for internal purposes
1866                  */
1867                 seq->wParam = winpos->flags & 0xffff;
1868                 /* We are not interested in the flags that don't match under XP and Win9x */
1869                 seq->wParam &= ~SWP_NOZORDER;
1870                 break;
1871             }
1872
1873             case WM_DRAWITEM:
1874             {
1875                 DRAW_ITEM_STRUCT di;
1876                 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)msg->lParam;
1877
1878                 sprintf( seq->output, "%s: %p WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x",
1879                          msg->descr, msg->hwnd, dis->CtlType, dis->CtlID,
1880                          dis->itemID, dis->itemAction, dis->itemState);
1881
1882                 di.u.lp = 0;
1883                 di.u.item.type = dis->CtlType;
1884                 di.u.item.ctl_id = dis->CtlID;
1885                 if (dis->CtlType == ODT_LISTBOX ||
1886                     dis->CtlType == ODT_COMBOBOX ||
1887                     dis->CtlType == ODT_MENU)
1888                     di.u.item.item_id = dis->itemID;
1889                 di.u.item.action = dis->itemAction;
1890                 di.u.item.state = dis->itemState;
1891
1892                 seq->lParam = di.u.lp;
1893                 break;
1894             }
1895             default:
1896                 if (msg->message >= 0xc000) return;  /* ignore registered messages */
1897                 sprintf( seq->output, "%s: %p %04x wp %08lx lp %08lx",
1898                          msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
1899             }
1900             if (msg->flags & (sent|posted|parent|defwinproc|beginpaint))
1901                 sprintf( seq->output + strlen(seq->output), " (flags %x)", msg->flags );
1902         }
1903     }
1904
1905     sequence_cnt++;
1906 }
1907
1908 /* try to make sure pending X events have been processed before continuing */
1909 static void flush_events(void)
1910 {
1911     MSG msg;
1912     int diff = 200;
1913     int min_timeout = 100;
1914     DWORD time = GetTickCount() + diff;
1915
1916     while (diff > 0)
1917     {
1918         if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
1919         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
1920         diff = time - GetTickCount();
1921     }
1922 }
1923
1924 static void flush_sequence(void)
1925 {
1926     HeapFree(GetProcessHeap(), 0, sequence);
1927     sequence = 0;
1928     sequence_cnt = sequence_size = 0;
1929 }
1930
1931 static void dump_sequence(const struct message *expected, const char *context, const char *file, int line)
1932 {
1933     const struct recvd_message *actual = sequence;
1934     unsigned int count = 0;
1935
1936     trace_(file, line)("Failed sequence %s:\n", context );
1937     while (expected->message && actual->message)
1938     {
1939         if (actual->output[0])
1940         {
1941             if (expected->flags & hook)
1942             {
1943                 trace_(file, line)( "  %u: expected: hook %04x - actual: %s\n",
1944                                     count, expected->message, actual->output );
1945             }
1946             else if (expected->flags & winevent_hook)
1947             {
1948                 trace_(file, line)( "  %u: expected: winevent %04x - actual: %s\n",
1949                                     count, expected->message, actual->output );
1950             }
1951             else if (expected->flags & kbd_hook)
1952             {
1953                 trace_(file, line)( "  %u: expected: kbd %04x - actual: %s\n",
1954                                     count, expected->message, actual->output );
1955             }
1956             else
1957             {
1958                 trace_(file, line)( "  %u: expected: msg %04x - actual: %s\n",
1959                                     count, expected->message, actual->output );
1960             }
1961         }
1962
1963         if (expected->message == actual->message)
1964         {
1965             if ((expected->flags & defwinproc) != (actual->flags & defwinproc) &&
1966                 (expected->flags & optional))
1967             {
1968                 /* don't match messages if their defwinproc status differs */
1969                 expected++;
1970             }
1971             else
1972             {
1973                 expected++;
1974                 actual++;
1975             }
1976         }
1977         /* silently drop winevent messages if there is no support for them */
1978         else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
1979             expected++;
1980         else
1981         {
1982             expected++;
1983             actual++;
1984         }
1985         count++;
1986     }
1987
1988     /* optional trailing messages */
1989     while (expected->message && ((expected->flags & optional) ||
1990             ((expected->flags & winevent_hook) && !hEvent_hook)))
1991     {
1992         trace_(file, line)( "  %u: expected: msg %04x - actual: nothing\n", count, expected->message );
1993         expected++;
1994         count++;
1995     }
1996
1997     if (expected->message)
1998     {
1999         trace_(file, line)( "  %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2000         return;
2001     }
2002
2003     while (actual->message && actual->output[0])
2004     {
2005         trace_(file, line)( "  %u: expected: nothing - actual: %s\n", count, actual->output );
2006         actual++;
2007         count++;
2008     }
2009 }
2010
2011 #define ok_sequence( exp, contx, todo) \
2012         ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
2013
2014
2015 static void ok_sequence_(const struct message *expected_list, const char *context, int todo,
2016                          const char *file, int line)
2017 {
2018     static const struct recvd_message end_of_sequence;
2019     const struct message *expected = expected_list;
2020     const struct recvd_message *actual;
2021     int failcount = 0, dump = 0;
2022     unsigned int count = 0;
2023
2024     add_message(&end_of_sequence);
2025
2026     actual = sequence;
2027
2028     while (expected->message && actual->message)
2029     {
2030         if (expected->message == actual->message &&
2031             !((expected->flags ^ actual->flags) & (hook|winevent_hook|kbd_hook)))
2032         {
2033             if (expected->flags & wparam)
2034             {
2035                 if (((expected->wParam ^ actual->wParam) & ~expected->wp_mask) && todo)
2036                 {
2037                     todo_wine {
2038                         failcount ++;
2039                         if (strcmp(winetest_platform, "wine")) dump++;
2040                         ok_( file, line) (FALSE,
2041                             "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2042                             context, count, expected->message, expected->wParam, actual->wParam);
2043                     }
2044                 }
2045                 else
2046                 {
2047                     ok_( file, line)( ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) == 0,
2048                                      "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2049                                      context, count, expected->message, expected->wParam, actual->wParam);
2050                     if ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) dump++;
2051                 }
2052
2053             }
2054             if (expected->flags & lparam)
2055             {
2056                 if (((expected->lParam ^ actual->lParam) & ~expected->lp_mask) && todo)
2057                 {
2058                     todo_wine {
2059                         failcount ++;
2060                         if (strcmp(winetest_platform, "wine")) dump++;
2061                         ok_( file, line) (FALSE,
2062                             "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2063                             context, count, expected->message, expected->lParam, actual->lParam);
2064                     }
2065                 }
2066                 else
2067                 {
2068                     ok_( file, line)(((expected->lParam ^ actual->lParam) & ~expected->lp_mask) == 0,
2069                                      "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2070                                      context, count, expected->message, expected->lParam, actual->lParam);
2071                     if ((expected->lParam ^ actual->lParam) & ~expected->lp_mask) dump++;
2072                 }
2073             }
2074             if ((expected->flags & optional) &&
2075                 ((expected->flags ^ actual->flags) & (defwinproc|parent)))
2076             {
2077                 /* don't match optional messages if their defwinproc or parent status differs */
2078                 expected++;
2079                 count++;
2080                 continue;
2081             }
2082             if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
2083             {
2084                     todo_wine {
2085                         failcount ++;
2086                         if (strcmp(winetest_platform, "wine")) dump++;
2087                         ok_( file, line) (FALSE,
2088                             "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2089                             context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2090                     }
2091             }
2092             else
2093             {
2094                 ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
2095                     "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2096                     context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2097                 if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) dump++;
2098             }
2099
2100             ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
2101                 "%s: %u: the msg 0x%04x should %shave been sent by BeginPaint\n",
2102                 context, count, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
2103             if ((expected->flags & beginpaint) != (actual->flags & beginpaint)) dump++;
2104
2105             ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
2106                 "%s: %u: the msg 0x%04x should have been %s\n",
2107                 context, count, expected->message, (expected->flags & posted) ? "posted" : "sent");
2108             if ((expected->flags & (sent|posted)) != (actual->flags & (sent|posted))) dump++;
2109
2110             ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
2111                 "%s: %u: the msg 0x%04x was expected in %s\n",
2112                 context, count, expected->message, (expected->flags & parent) ? "parent" : "child");
2113             if ((expected->flags & parent) != (actual->flags & parent)) dump++;
2114
2115             ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
2116                 "%s: %u: the msg 0x%04x should have been sent by a hook\n",
2117                 context, count, expected->message);
2118             if ((expected->flags & hook) != (actual->flags & hook)) dump++;
2119
2120             ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
2121                 "%s: %u: the msg 0x%04x should have been sent by a winevent hook\n",
2122                 context, count, expected->message);
2123             if ((expected->flags & winevent_hook) != (actual->flags & winevent_hook)) dump++;
2124
2125             ok_( file, line) ((expected->flags & kbd_hook) == (actual->flags & kbd_hook),
2126                 "%s: %u: the msg 0x%04x should have been sent by a keyboard hook\n",
2127                 context, count, expected->message);
2128             if ((expected->flags & kbd_hook) != (actual->flags & kbd_hook)) dump++;
2129
2130             expected++;
2131             actual++;
2132         }
2133         /* silently drop hook messages if there is no support for them */
2134         else if ((expected->flags & optional) ||
2135                  ((expected->flags & hook) && !hCBT_hook) ||
2136                  ((expected->flags & winevent_hook) && !hEvent_hook) ||
2137                  ((expected->flags & kbd_hook) && !hKBD_hook))
2138             expected++;
2139         else if (todo)
2140         {
2141             failcount++;
2142             todo_wine {
2143                 if (strcmp(winetest_platform, "wine")) dump++;
2144                 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2145                                   context, count, expected->message, actual->message);
2146             }
2147             goto done;
2148         }
2149         else
2150         {
2151             ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2152                               context, count, expected->message, actual->message);
2153             dump++;
2154             expected++;
2155             actual++;
2156         }
2157         count++;
2158     }
2159
2160     /* skip all optional trailing messages */
2161     while (expected->message && ((expected->flags & optional) ||
2162                                  ((expected->flags & hook) && !hCBT_hook) ||
2163                                  ((expected->flags & winevent_hook) && !hEvent_hook)))
2164         expected++;
2165
2166     if (todo)
2167     {
2168         todo_wine {
2169             if (expected->message || actual->message) {
2170                 failcount++;
2171                 if (strcmp(winetest_platform, "wine")) dump++;
2172                 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2173                                   context, count, expected->message, actual->message);
2174             }
2175         }
2176     }
2177     else
2178     {
2179         if (expected->message || actual->message)
2180         {
2181             dump++;
2182             ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2183                               context, count, expected->message, actual->message);
2184         }
2185     }
2186     if( todo && !failcount) /* succeeded yet marked todo */
2187         todo_wine {
2188             if (!strcmp(winetest_platform, "wine")) dump++;
2189             ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
2190         }
2191
2192 done:
2193     if (dump) dump_sequence(expected_list, context, file, line);
2194     flush_sequence();
2195 }
2196
2197 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT))
2198
2199 /******************************** MDI test **********************************/
2200
2201 /* CreateWindow for MDI frame window, initially visible */
2202 static const struct message WmCreateMDIframeSeq[] = {
2203     { HCBT_CREATEWND, hook },
2204     { WM_GETMINMAXINFO, sent },
2205     { WM_NCCREATE, sent },
2206     { WM_NCCALCSIZE, sent|wparam, 0 },
2207     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2208     { WM_CREATE, sent },
2209     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2210     { WM_NOTIFYFORMAT, sent|optional },
2211     { WM_QUERYUISTATE, sent|optional },
2212     { WM_WINDOWPOSCHANGING, sent|optional },
2213     { WM_GETMINMAXINFO, sent|optional },
2214     { WM_NCCALCSIZE, sent|optional },
2215     { WM_WINDOWPOSCHANGED, sent|optional },
2216     { WM_SHOWWINDOW, sent|wparam, 1 },
2217     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2218     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2219     { HCBT_ACTIVATE, hook },
2220     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
2221     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
2222     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
2223     { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
2224     { WM_NCACTIVATE, sent },
2225     { WM_GETTEXT, sent|defwinproc|optional },
2226     { WM_ACTIVATE, sent|wparam, 1 },
2227     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
2228     { HCBT_SETFOCUS, hook },
2229     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2230     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2231     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2232     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
2233     /* Win9x adds SWP_NOZORDER below */
2234     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2235     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2236     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2237     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2238     { WM_MOVE, sent },
2239     { 0 }
2240 };
2241 /* DestroyWindow for MDI frame window, initially visible */
2242 static const struct message WmDestroyMDIframeSeq[] = {
2243     { HCBT_DESTROYWND, hook },
2244     { 0x0090, sent|optional },
2245     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2246     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2247     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2248     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2249     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
2250     { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2251     { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
2252     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
2253     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2254     { WM_DESTROY, sent },
2255     { WM_NCDESTROY, sent },
2256     { 0 }
2257 };
2258 /* CreateWindow for MDI client window, initially visible */
2259 static const struct message WmCreateMDIclientSeq[] = {
2260     { HCBT_CREATEWND, hook },
2261     { WM_NCCREATE, sent },
2262     { WM_NCCALCSIZE, sent|wparam, 0 },
2263     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2264     { WM_CREATE, sent },
2265     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2266     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2267     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2268     { WM_MOVE, sent },
2269     { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
2270     { WM_SHOWWINDOW, sent|wparam, 1 },
2271     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2272     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2273     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2274     { 0 }
2275 };
2276 /* ShowWindow(SW_SHOW) for MDI client window */
2277 static const struct message WmShowMDIclientSeq[] = {
2278     { WM_SHOWWINDOW, sent|wparam, 1 },
2279     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2280     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2281     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2282     { 0 }
2283 };
2284 /* ShowWindow(SW_HIDE) for MDI client window */
2285 static const struct message WmHideMDIclientSeq[] = {
2286     { WM_SHOWWINDOW, sent|wparam, 0 },
2287     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2288     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
2289     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
2290     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2291     { 0 }
2292 };
2293 /* DestroyWindow for MDI client window, initially visible */
2294 static const struct message WmDestroyMDIclientSeq[] = {
2295     { HCBT_DESTROYWND, hook },
2296     { 0x0090, sent|optional },
2297     { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
2298     { WM_SHOWWINDOW, sent|wparam, 0 },
2299     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2300     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2301     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2302     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2303     { WM_DESTROY, sent },
2304     { WM_NCDESTROY, sent },
2305     { 0 }
2306 };
2307 /* CreateWindow for MDI child window, initially visible */
2308 static const struct message WmCreateMDIchildVisibleSeq[] = {
2309     { HCBT_CREATEWND, hook },
2310     { WM_NCCREATE, sent }, 
2311     { WM_NCCALCSIZE, sent|wparam, 0 },
2312     { WM_CREATE, sent },
2313     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2314     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2315     { WM_MOVE, sent },
2316     /* Win2k sends wparam set to
2317      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2318      * while Win9x doesn't bother to set child window id according to
2319      * CLIENTCREATESTRUCT.idFirstChild
2320      */
2321     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2322     { WM_SHOWWINDOW, sent|wparam, 1 },
2323     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2324     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2325     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2326     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2327     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2328     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2329     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2330
2331     /* Win9x: message sequence terminates here. */
2332
2333     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2334     { HCBT_SETFOCUS, hook }, /* in MDI client */
2335     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2336     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2337     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2338     { WM_SETFOCUS, sent }, /* in MDI client */
2339     { HCBT_SETFOCUS, hook },
2340     { WM_KILLFOCUS, sent }, /* in MDI client */
2341     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2342     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2343     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2344     { WM_SETFOCUS, sent|defwinproc },
2345     { WM_MDIACTIVATE, sent|defwinproc },
2346     { 0 }
2347 };
2348 /* CreateWindow for MDI child window with invisible parent */
2349 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
2350     { HCBT_CREATEWND, hook },
2351     { WM_GETMINMAXINFO, sent },
2352     { WM_NCCREATE, sent }, 
2353     { WM_NCCALCSIZE, sent|wparam, 0 },
2354     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2355     { WM_CREATE, sent },
2356     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2357     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2358     { WM_MOVE, sent },
2359     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2360     { WM_SHOWWINDOW, sent|wparam, 1 },
2361     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2362     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2363     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2364     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2365
2366     /* Win9x: message sequence terminates here. */
2367
2368     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2369     { HCBT_SETFOCUS, hook }, /* in MDI client */
2370     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2371     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2372     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2373     { WM_SETFOCUS, sent }, /* in MDI client */
2374     { HCBT_SETFOCUS, hook },
2375     { WM_KILLFOCUS, sent }, /* in MDI client */
2376     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2377     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2378     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2379     { WM_SETFOCUS, sent|defwinproc },
2380     { WM_MDIACTIVATE, sent|defwinproc },
2381     { 0 }
2382 };
2383 /* DestroyWindow for MDI child window, initially visible */
2384 static const struct message WmDestroyMDIchildVisibleSeq[] = {
2385     { HCBT_DESTROYWND, hook },
2386     /* Win2k sends wparam set to
2387      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2388      * while Win9x doesn't bother to set child window id according to
2389      * CLIENTCREATESTRUCT.idFirstChild
2390      */
2391     { 0x0090, sent|optional },
2392     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2393     { WM_SHOWWINDOW, sent|wparam, 0 },
2394     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2395     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2396     { WM_ERASEBKGND, sent|parent|optional },
2397     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2398
2399     /* { WM_DESTROY, sent }
2400      * Win9x: message sequence terminates here.
2401      */
2402
2403     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2404     { WM_KILLFOCUS, sent },
2405     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2406     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2407     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2408     { WM_SETFOCUS, sent }, /* in MDI client */
2409
2410     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2411     { WM_KILLFOCUS, sent }, /* in MDI client */
2412     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2413     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2414     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2415     { WM_SETFOCUS, sent }, /* in MDI client */
2416
2417     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2418
2419     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2420     { WM_KILLFOCUS, sent },
2421     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2422     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2423     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2424     { WM_SETFOCUS, sent }, /* in MDI client */
2425
2426     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2427     { WM_KILLFOCUS, sent }, /* in MDI client */
2428     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2429     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2430     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2431     { WM_SETFOCUS, sent }, /* in MDI client */
2432
2433     { WM_DESTROY, sent },
2434
2435     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2436     { WM_KILLFOCUS, sent },
2437     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2438     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2439     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2440     { WM_SETFOCUS, sent }, /* in MDI client */
2441
2442     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2443     { WM_KILLFOCUS, sent }, /* in MDI client */
2444     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2445     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2446     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2447     { WM_SETFOCUS, sent }, /* in MDI client */
2448
2449     { WM_NCDESTROY, sent },
2450     { 0 }
2451 };
2452 /* CreateWindow for MDI child window, initially invisible */
2453 static const struct message WmCreateMDIchildInvisibleSeq[] = {
2454     { HCBT_CREATEWND, hook },
2455     { WM_NCCREATE, sent }, 
2456     { WM_NCCALCSIZE, sent|wparam, 0 },
2457     { WM_CREATE, sent },
2458     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2459     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2460     { WM_MOVE, sent },
2461     /* Win2k sends wparam set to
2462      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2463      * while Win9x doesn't bother to set child window id according to
2464      * CLIENTCREATESTRUCT.idFirstChild
2465      */
2466     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2467     { 0 }
2468 };
2469 /* DestroyWindow for MDI child window, initially invisible */
2470 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
2471     { HCBT_DESTROYWND, hook },
2472     /* Win2k sends wparam set to
2473      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2474      * while Win9x doesn't bother to set child window id according to
2475      * CLIENTCREATESTRUCT.idFirstChild
2476      */
2477     { 0x0090, sent|optional },
2478     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2479     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2480     { WM_DESTROY, sent },
2481     { WM_NCDESTROY, sent },
2482     /* FIXME: Wine destroys an icon/title window while Windows doesn't */
2483     { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */
2484     { 0 }
2485 };
2486 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
2487 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
2488     { HCBT_CREATEWND, hook },
2489     { WM_NCCREATE, sent }, 
2490     { WM_NCCALCSIZE, sent|wparam, 0 },
2491     { WM_CREATE, sent },
2492     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2493     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2494     { WM_MOVE, sent },
2495     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2496     { WM_GETMINMAXINFO, sent },
2497     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED  },
2498     { WM_NCCALCSIZE, sent|wparam, 1 },
2499     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2500     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2501      /* in MDI frame */
2502     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2503     { WM_NCCALCSIZE, sent|wparam, 1 },
2504     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2505     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2506     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2507     /* Win2k sends wparam set to
2508      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2509      * while Win9x doesn't bother to set child window id according to
2510      * CLIENTCREATESTRUCT.idFirstChild
2511      */
2512     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2513     { WM_SHOWWINDOW, sent|wparam, 1 },
2514     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2515     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2516     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2517     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2518     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2519     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2520     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_FRAMECHANGED },
2521
2522     /* Win9x: message sequence terminates here. */
2523
2524     { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
2525     { HCBT_SETFOCUS, hook|optional }, /* in MDI client */
2526     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2527     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2528     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2529     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2530     { HCBT_SETFOCUS, hook|optional },
2531     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
2532     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2533     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2534     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2535     { WM_SETFOCUS, sent|defwinproc|optional },
2536     { WM_MDIACTIVATE, sent|defwinproc|optional },
2537      /* in MDI frame */
2538     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2539     { WM_NCCALCSIZE, sent|wparam, 1 },
2540     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2541     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2542     { 0 }
2543 };
2544 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
2545 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
2546     /* restore the 1st MDI child */
2547     { WM_SETREDRAW, sent|wparam, 0 },
2548     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2549     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2550     { WM_NCCALCSIZE, sent|wparam, 1 },
2551     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2552     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2553     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2554      /* in MDI frame */
2555     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2556     { WM_NCCALCSIZE, sent|wparam, 1 },
2557     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2558     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2559     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2560     { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
2561     /* create the 2nd MDI child */
2562     { HCBT_CREATEWND, hook },
2563     { WM_NCCREATE, sent }, 
2564     { WM_NCCALCSIZE, sent|wparam, 0 },
2565     { WM_CREATE, sent },
2566     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2567     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2568     { WM_MOVE, sent },
2569     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2570     { WM_GETMINMAXINFO, sent },
2571     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2572     { WM_NCCALCSIZE, sent|wparam, 1 },
2573     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2574     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2575     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2576      /* in MDI frame */
2577     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2578     { WM_NCCALCSIZE, sent|wparam, 1 },
2579     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2580     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2581     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2582     /* Win2k sends wparam set to
2583      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2584      * while Win9x doesn't bother to set child window id according to
2585      * CLIENTCREATESTRUCT.idFirstChild
2586      */
2587     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2588     { WM_SHOWWINDOW, sent|wparam, 1 },
2589     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2590     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2591     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2592     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2593     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2594     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2595
2596     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2597     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2598
2599     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2600
2601     /* Win9x: message sequence terminates here. */
2602
2603     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2604     { HCBT_SETFOCUS, hook },
2605     { WM_KILLFOCUS, sent|defwinproc|optional }, /* in the 1st MDI child */
2606     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
2607     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2608     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2609     { WM_SETFOCUS, sent }, /* in MDI client */
2610     { HCBT_SETFOCUS, hook },
2611     { WM_KILLFOCUS, sent }, /* in MDI client */
2612     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2613     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2614     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2615     { WM_SETFOCUS, sent|defwinproc },
2616
2617     { WM_MDIACTIVATE, sent|defwinproc },
2618      /* in MDI frame */
2619     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2620     { WM_NCCALCSIZE, sent|wparam, 1 },
2621     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2622     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2623     { 0 }
2624 };
2625 /* WM_MDICREATE MDI child window, initially visible and maximized */
2626 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
2627     { WM_MDICREATE, sent },
2628     { HCBT_CREATEWND, hook },
2629     { WM_NCCREATE, sent }, 
2630     { WM_NCCALCSIZE, sent|wparam, 0 },
2631     { WM_CREATE, sent },
2632     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2633     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2634     { WM_MOVE, sent },
2635     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2636     { WM_GETMINMAXINFO, sent },
2637     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2638     { WM_NCCALCSIZE, sent|wparam, 1 },
2639     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2640     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2641
2642      /* in MDI frame */
2643     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2644     { WM_NCCALCSIZE, sent|wparam, 1 },
2645     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2646     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2647     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2648
2649     /* Win2k sends wparam set to
2650      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2651      * while Win9x doesn't bother to set child window id according to
2652      * CLIENTCREATESTRUCT.idFirstChild
2653      */
2654     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2655     { WM_SHOWWINDOW, sent|wparam, 1 },
2656     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2657
2658     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2659
2660     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2661     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2662     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2663
2664     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2665     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2666
2667     /* Win9x: message sequence terminates here. */
2668
2669     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2670     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2671     { HCBT_SETFOCUS, hook }, /* in MDI client */
2672     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2673     { WM_IME_NOTIFY, sent|wparam|optional, 2 },
2674     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
2675     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2676     { HCBT_SETFOCUS, hook|optional },
2677     { WM_KILLFOCUS, sent }, /* in MDI client */
2678     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2679     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2680     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2681     { WM_SETFOCUS, sent|defwinproc },
2682
2683     { WM_MDIACTIVATE, sent|defwinproc },
2684
2685      /* in MDI child */
2686     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2687     { WM_NCCALCSIZE, sent|wparam, 1 },
2688     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2689     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2690
2691      /* in MDI frame */
2692     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2693     { WM_NCCALCSIZE, sent|wparam, 1 },
2694     { 0x0093, sent|defwinproc|optional },
2695     { 0x0093, sent|defwinproc|optional },
2696     { 0x0093, sent|defwinproc|optional },
2697     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2698     { WM_MOVE, sent|defwinproc },
2699     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2700
2701      /* in MDI client */
2702     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2703     { WM_NCCALCSIZE, sent|wparam, 1 },
2704     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2705     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2706
2707      /* in MDI child */
2708     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2709     { WM_NCCALCSIZE, sent|wparam, 1 },
2710     { 0x0093, sent|optional },
2711     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2712     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2713
2714     { 0x0093, sent|optional },
2715     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2716     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2717     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
2718     { 0x0093, sent|defwinproc|optional },
2719     { 0x0093, sent|defwinproc|optional },
2720     { 0x0093, sent|defwinproc|optional },
2721     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2722     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2723
2724     { 0 }
2725 };
2726 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
2727 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
2728     { HCBT_CREATEWND, hook },
2729     { WM_GETMINMAXINFO, sent },
2730     { WM_NCCREATE, sent }, 
2731     { WM_NCCALCSIZE, sent|wparam, 0 },
2732     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2733     { WM_CREATE, sent },
2734     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2735     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2736     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOZORDER }, /* MDI frame */
2737     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI frame */
2738     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOZORDER }, /* MDI frame */
2739     { WM_MOVE, sent },
2740     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2741     { WM_GETMINMAXINFO, sent },
2742     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2743     { WM_GETMINMAXINFO, sent|defwinproc },
2744     { WM_NCCALCSIZE, sent|wparam, 1 },
2745     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_STATECHANGED },
2746     { WM_MOVE, sent|defwinproc },
2747     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2748      /* in MDI frame */
2749     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2750     { WM_NCCALCSIZE, sent|wparam, 1 },
2751     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2752     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2753     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
2754     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2755     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2756     /* Win2k sends wparam set to
2757      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2758      * while Win9x doesn't bother to set child window id according to
2759      * CLIENTCREATESTRUCT.idFirstChild
2760      */
2761     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2762     { 0 }
2763 };
2764 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
2765 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
2766     { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
2767     { HCBT_SYSCOMMAND, hook },
2768     { WM_CLOSE, sent|defwinproc },
2769     { WM_MDIDESTROY, sent }, /* in MDI client */
2770
2771     /* bring the 1st MDI child to top */
2772     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
2773     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
2774
2775     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2776
2777     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
2778     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2779     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2780
2781     /* maximize the 1st MDI child */
2782     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2783     { WM_GETMINMAXINFO, sent|defwinproc },
2784     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED },
2785     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2786     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
2787     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2788     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2789
2790     /* restore the 2nd MDI child */
2791     { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
2792     { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
2793     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
2794     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2795
2796     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2797
2798     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2799     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2800
2801     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2802
2803     { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
2804      /* in MDI frame */
2805     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2806     { WM_NCCALCSIZE, sent|wparam, 1 },
2807     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2808     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2809     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2810
2811     /* bring the 1st MDI child to top */
2812     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2813     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2814     { HCBT_SETFOCUS, hook },
2815     { WM_KILLFOCUS, sent|defwinproc },
2816     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
2817     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2818     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2819     { WM_SETFOCUS, sent }, /* in MDI client */
2820     { HCBT_SETFOCUS, hook },
2821     { WM_KILLFOCUS, sent }, /* in MDI client */
2822     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2823     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2824     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2825     { WM_SETFOCUS, sent|defwinproc },
2826     { WM_MDIACTIVATE, sent|defwinproc },
2827     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2828
2829     /* apparently ShowWindow(SW_SHOW) on an MDI client */
2830     { WM_SHOWWINDOW, sent|wparam, 1 },
2831     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2832     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2833     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2834     { WM_MDIREFRESHMENU, sent },
2835
2836     { HCBT_DESTROYWND, hook },
2837     /* Win2k sends wparam set to
2838      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2839      * while Win9x doesn't bother to set child window id according to
2840      * CLIENTCREATESTRUCT.idFirstChild
2841      */
2842     { 0x0090, sent|defwinproc|optional },
2843     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2844     { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
2845     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2846     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2847     { WM_ERASEBKGND, sent|parent|optional },
2848     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2849
2850     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2851     { WM_DESTROY, sent|defwinproc },
2852     { WM_NCDESTROY, sent|defwinproc },
2853     { 0 }
2854 };
2855 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
2856 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
2857     { WM_MDIDESTROY, sent }, /* in MDI client */
2858     { WM_SHOWWINDOW, sent|wparam, 0 },
2859     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2860     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2861     { WM_ERASEBKGND, sent|parent|optional },
2862     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2863
2864     { HCBT_SETFOCUS, hook },
2865     { WM_KILLFOCUS, sent },
2866     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2867     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2868     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2869     { WM_SETFOCUS, sent }, /* in MDI client */
2870     { HCBT_SETFOCUS, hook },
2871     { WM_KILLFOCUS, sent }, /* in MDI client */
2872     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2873     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2874     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2875     { WM_SETFOCUS, sent },
2876
2877      /* in MDI child */
2878     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2879     { WM_NCCALCSIZE, sent|wparam, 1 },
2880     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2881     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2882
2883      /* in MDI frame */
2884     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2885     { WM_NCCALCSIZE, sent|wparam, 1 },
2886     { 0x0093, sent|defwinproc|optional },
2887     { 0x0093, sent|defwinproc|optional },
2888     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2889     { WM_MOVE, sent|defwinproc },
2890     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2891
2892      /* in MDI client */
2893     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2894     { WM_NCCALCSIZE, sent|wparam, 1 },
2895     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2896     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2897
2898      /* in MDI child */
2899     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2900     { WM_NCCALCSIZE, sent|wparam, 1 },
2901     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2902     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2903
2904      /* in MDI child */
2905     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2906     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2907     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2908     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2909
2910      /* in MDI frame */
2911     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2912     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2913     { 0x0093, sent|defwinproc|optional },
2914     { 0x0093, sent|defwinproc|optional },
2915     { 0x0093, sent|defwinproc|optional },
2916     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2917     { WM_MOVE, sent|defwinproc },
2918     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2919
2920      /* in MDI client */
2921     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2922     { WM_NCCALCSIZE, sent|wparam, 1 },
2923     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2924     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2925
2926      /* in MDI child */
2927     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
2928     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2929     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2930     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2931     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2932     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2933
2934     { 0x0093, sent|defwinproc|optional },
2935     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
2936     { 0x0093, sent|defwinproc|optional },
2937     { 0x0093, sent|defwinproc|optional },
2938     { 0x0093, sent|defwinproc|optional },
2939     { 0x0093, sent|optional },
2940
2941     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2942     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2943     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2944     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2945     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2946
2947      /* in MDI frame */
2948     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2949     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
2950     { 0x0093, sent|defwinproc|optional },
2951     { 0x0093, sent|defwinproc|optional },
2952     { 0x0093, sent|defwinproc|optional },
2953     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2954     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2955     { 0x0093, sent|optional },
2956
2957     { WM_NCACTIVATE, sent|wparam, 0 },
2958     { WM_MDIACTIVATE, sent },
2959
2960     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2961     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
2962     { WM_NCCALCSIZE, sent|wparam, 1 },
2963
2964     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2965
2966     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2967     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2968     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2969
2970      /* in MDI child */
2971     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2972     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2973     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2974     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2975
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 },
2980     { WM_MOVE, sent|defwinproc },
2981     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2982
2983      /* in MDI client */
2984     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2985     { WM_NCCALCSIZE, sent|wparam, 1 },
2986     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2987     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2988     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2989     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2990     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2991     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2992     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2993
2994     { HCBT_SETFOCUS, hook },
2995     { WM_KILLFOCUS, sent },
2996     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2997     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2998     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2999     { WM_SETFOCUS, sent }, /* in MDI client */
3000
3001     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
3002
3003     { HCBT_DESTROYWND, hook },
3004     /* Win2k sends wparam set to
3005      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3006      * while Win9x doesn't bother to set child window id according to
3007      * CLIENTCREATESTRUCT.idFirstChild
3008      */
3009     { 0x0090, sent|optional },
3010     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3011
3012     { WM_SHOWWINDOW, sent|wparam, 0 },
3013     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3014     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3015     { WM_ERASEBKGND, sent|parent|optional },
3016     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3017
3018     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
3019     { WM_DESTROY, sent },
3020     { WM_NCDESTROY, sent },
3021     { 0 }
3022 };
3023 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
3024 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
3025     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3026     { WM_GETMINMAXINFO, sent },
3027     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3028     { WM_NCCALCSIZE, sent|wparam, 1 },
3029     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3030     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3031
3032     { WM_WINDOWPOSCHANGING, sent|wparam|optional|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3033     { WM_NCACTIVATE, sent|wparam|optional|defwinproc, 1 },
3034     { HCBT_SETFOCUS, hook|optional },
3035     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3036     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3037     { WM_SETFOCUS, sent|optional }, /* in MDI client */
3038     { HCBT_SETFOCUS, hook|optional },
3039     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3040     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3041     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3042     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3043     { WM_SETFOCUS, sent|optional|defwinproc },
3044     { WM_MDIACTIVATE, sent|optional|defwinproc },
3045     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3046     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3047      /* in MDI frame */
3048     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3049     { WM_NCCALCSIZE, sent|wparam, 1 },
3050     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3051     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3052     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3053     { 0 }
3054 };
3055 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
3056 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
3057     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3058     { WM_GETMINMAXINFO, sent },
3059     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
3060     { WM_GETMINMAXINFO, sent|defwinproc },
3061     { WM_NCCALCSIZE, sent|wparam, 1 },
3062     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3063     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3064
3065     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3066     { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
3067     { HCBT_SETFOCUS, hook|optional },
3068     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3069     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3070     { WM_SETFOCUS, sent|optional }, /* in MDI client */
3071     { HCBT_SETFOCUS, hook|optional },
3072     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3073     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3074     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3075     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3076     { WM_SETFOCUS, sent|defwinproc|optional },
3077     { WM_MDIACTIVATE, sent|defwinproc|optional },
3078     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3079     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3080     { 0 }
3081 };
3082 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
3083 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
3084     { WM_MDIMAXIMIZE, sent }, /* in MDI client */
3085     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3086     { WM_GETMINMAXINFO, sent },
3087     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3088     { WM_GETMINMAXINFO, sent|defwinproc },
3089     { WM_NCCALCSIZE, sent|wparam, 1 },
3090     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
3091     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3092     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
3093     { WM_MOVE, sent|defwinproc },
3094     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3095
3096     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3097     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3098     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3099     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3100     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3101     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3102      /* in MDI frame */
3103     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3104     { WM_NCCALCSIZE, sent|wparam, 1 },
3105     { 0x0093, sent|defwinproc|optional },
3106     { 0x0094, sent|defwinproc|optional },
3107     { 0x0094, sent|defwinproc|optional },
3108     { 0x0094, sent|defwinproc|optional },
3109     { 0x0094, sent|defwinproc|optional },
3110     { 0x0093, sent|defwinproc|optional },
3111     { 0x0093, sent|defwinproc|optional },
3112     { 0x0091, sent|defwinproc|optional },
3113     { 0x0092, sent|defwinproc|optional },
3114     { 0x0092, sent|defwinproc|optional },
3115     { 0x0092, sent|defwinproc|optional },
3116     { 0x0092, sent|defwinproc|optional },
3117     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3118     { WM_MOVE, sent|defwinproc },
3119     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3120     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
3121      /* in MDI client */
3122     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3123     { WM_NCCALCSIZE, sent|wparam, 1 },
3124     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3125     { WM_SIZE, sent|wparam, SIZE_RESTORED },
3126      /* in MDI child */
3127     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3128     { WM_GETMINMAXINFO, sent|defwinproc },
3129     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3130     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3131     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3132     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
3133     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3134     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3135     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3136     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3137      /* in MDI frame */
3138     { 0x0093, sent|optional },
3139     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3140     { 0x0093, sent|defwinproc|optional },
3141     { 0x0093, sent|defwinproc|optional },
3142     { 0x0093, sent|defwinproc|optional },
3143     { 0x0091, sent|defwinproc|optional },
3144     { 0x0092, sent|defwinproc|optional },
3145     { 0x0092, sent|defwinproc|optional },
3146     { 0x0092, sent|defwinproc|optional },
3147     { 0x0092, sent|defwinproc|optional },
3148     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3149     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3150     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3151     { 0 }
3152 };
3153 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
3154 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
3155     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3156     { WM_GETMINMAXINFO, sent },
3157     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3158     { WM_NCCALCSIZE, sent|wparam, 1 },
3159     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3160     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3161     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3162      /* in MDI frame */
3163     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3164     { WM_NCCALCSIZE, sent|wparam, 1 },
3165     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3166     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3167     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3168     { 0 }
3169 };
3170 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
3171 static const struct message WmRestoreMDIchildVisibleSeq[] = {
3172     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3173     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3174     { WM_NCCALCSIZE, sent|wparam, 1 },
3175     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3176     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3177     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3178      /* in MDI frame */
3179     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3180     { WM_NCCALCSIZE, sent|wparam, 1 },
3181     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3182     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3183     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3184     { 0 }
3185 };
3186 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
3187 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
3188     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3189     { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
3190     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3191     { WM_NCCALCSIZE, sent|wparam, 1 },
3192     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3193     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3194     { WM_MOVE, sent|defwinproc },
3195     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3196     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3197     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3198     { HCBT_SETFOCUS, hook },
3199     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3200     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
3201     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3202     { WM_SETFOCUS, sent },
3203     { 0 }
3204 };
3205 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
3206 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
3207     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
3208     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3209     { WM_NCCALCSIZE, sent|wparam, 1 },
3210     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3211     { WM_MOVE, sent|defwinproc },
3212     { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
3213     { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
3214     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3215     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3216     /* FIXME: Wine creates an icon/title window while Windows doesn't */
3217     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */
3218     { 0 }
3219 };
3220 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
3221 static const struct message WmRestoreMDIchildInisibleSeq[] = {
3222     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3223     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED  },
3224     { WM_NCCALCSIZE, sent|wparam, 1 },
3225     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3226     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3227     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3228     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3229      /* in MDI frame */
3230     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3231     { WM_NCCALCSIZE, sent|wparam, 1 },
3232     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3233     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3234     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3235     { 0 }
3236 };
3237
3238 static HWND mdi_client;
3239 static WNDPROC old_mdi_client_proc;
3240
3241 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3242 {
3243     struct recvd_message msg;
3244
3245     /* do not log painting messages */
3246     if (message != WM_PAINT &&
3247         message != WM_NCPAINT &&
3248         message != WM_SYNCPAINT &&
3249         message != WM_ERASEBKGND &&
3250         message != WM_NCHITTEST &&
3251         message != WM_GETTEXT &&
3252         message != WM_MDIGETACTIVE &&
3253         !ignore_message( message ))
3254     {
3255         msg.hwnd = hwnd;
3256         msg.message = message;
3257         msg.flags = sent|wparam|lparam;
3258         msg.wParam = wParam;
3259         msg.lParam = lParam;
3260         msg.descr = "mdi client";
3261         add_message(&msg);
3262     }
3263
3264     return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
3265 }
3266
3267 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3268 {
3269     static LONG defwndproc_counter = 0;
3270     LRESULT ret;
3271     struct recvd_message msg;
3272
3273     /* do not log painting messages */
3274     if (message != WM_PAINT &&
3275         message != WM_NCPAINT &&
3276         message != WM_SYNCPAINT &&
3277         message != WM_ERASEBKGND &&
3278         message != WM_NCHITTEST &&
3279         message != WM_GETTEXT &&
3280         !ignore_message( message ))
3281     {
3282         switch (message)
3283         {
3284             case WM_MDIACTIVATE:
3285             {
3286                 HWND active, client = GetParent(hwnd);
3287
3288                 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
3289
3290                 if (hwnd == (HWND)lParam) /* if we are being activated */
3291                     ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
3292                 else
3293                     ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
3294                 break;
3295             }
3296         }
3297
3298         msg.hwnd = hwnd;
3299         msg.message = message;
3300         msg.flags = sent|wparam|lparam;
3301         if (defwndproc_counter) msg.flags |= defwinproc;
3302         msg.wParam = wParam;
3303         msg.lParam = lParam;
3304         msg.descr = "mdi child";
3305         add_message(&msg);
3306     }
3307
3308     defwndproc_counter++;
3309     ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
3310     defwndproc_counter--;
3311
3312     return ret;
3313 }
3314
3315 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3316 {
3317     static LONG defwndproc_counter = 0;
3318     LRESULT ret;
3319     struct recvd_message msg;
3320
3321     /* do not log painting messages */
3322     if (message != WM_PAINT &&
3323         message != WM_NCPAINT &&
3324         message != WM_SYNCPAINT &&
3325         message != WM_ERASEBKGND &&
3326         message != WM_NCHITTEST &&
3327         message != WM_GETTEXT &&
3328         !ignore_message( message ))
3329     {
3330         msg.hwnd = hwnd;
3331         msg.message = message;
3332         msg.flags = sent|wparam|lparam;
3333         if (defwndproc_counter) msg.flags |= defwinproc;
3334         msg.wParam = wParam;
3335         msg.lParam = lParam;
3336         msg.descr = "mdi frame";
3337         add_message(&msg);
3338     }
3339
3340     defwndproc_counter++;
3341     ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
3342     defwndproc_counter--;
3343
3344     return ret;
3345 }
3346
3347 static BOOL mdi_RegisterWindowClasses(void)
3348 {
3349     WNDCLASSA cls;
3350
3351     cls.style = 0;
3352     cls.lpfnWndProc = mdi_frame_wnd_proc;
3353     cls.cbClsExtra = 0;
3354     cls.cbWndExtra = 0;
3355     cls.hInstance = GetModuleHandleA(0);
3356     cls.hIcon = 0;
3357     cls.hCursor = LoadCursorA(0, IDC_ARROW);
3358     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
3359     cls.lpszMenuName = NULL;
3360     cls.lpszClassName = "MDI_frame_class";
3361     if (!RegisterClassA(&cls)) return FALSE;
3362
3363     cls.lpfnWndProc = mdi_child_wnd_proc;
3364     cls.lpszClassName = "MDI_child_class";
3365     if (!RegisterClassA(&cls)) return FALSE;
3366
3367     if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
3368     old_mdi_client_proc = cls.lpfnWndProc;
3369     cls.hInstance = GetModuleHandleA(0);
3370     cls.lpfnWndProc = mdi_client_hook_proc;
3371     cls.lpszClassName = "MDI_client_class";
3372     if (!RegisterClassA(&cls)) assert(0);
3373
3374     return TRUE;
3375 }
3376
3377 static void test_mdi_messages(void)
3378 {
3379     MDICREATESTRUCTA mdi_cs;
3380     CLIENTCREATESTRUCT client_cs;
3381     HWND mdi_frame, mdi_child, mdi_child2, active_child;
3382     BOOL zoomed;
3383     RECT rc;
3384     HMENU hMenu = CreateMenu();
3385
3386     if (!mdi_RegisterWindowClasses()) assert(0);
3387
3388     flush_sequence();
3389
3390     trace("creating MDI frame window\n");
3391     mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
3392                                 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
3393                                 WS_MAXIMIZEBOX | WS_VISIBLE,
3394                                 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
3395                                 GetDesktopWindow(), hMenu,
3396                                 GetModuleHandleA(0), NULL);
3397     assert(mdi_frame);
3398     ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
3399
3400     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3401     ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
3402
3403     trace("creating MDI client window\n");
3404     GetClientRect(mdi_frame, &rc);
3405     client_cs.hWindowMenu = 0;
3406     client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
3407     mdi_client = CreateWindowExA(0, "MDI_client_class",
3408                                  NULL,
3409                                  WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
3410                                  rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
3411                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3412     assert(mdi_client);
3413     ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
3414
3415     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3416     ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
3417
3418     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3419     ok(!active_child, "wrong active MDI child %p\n", active_child);
3420     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3421
3422     SetFocus(0);
3423     flush_sequence();
3424
3425     trace("creating invisible MDI child window\n");
3426     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3427                                 WS_CHILD,
3428                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3429                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3430     assert(mdi_child);
3431
3432     flush_sequence();
3433     ShowWindow(mdi_child, SW_SHOWNORMAL);
3434     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
3435
3436     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3437     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3438
3439     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3440     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3441
3442     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3443     ok(!active_child, "wrong active MDI child %p\n", active_child);
3444     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3445
3446     ShowWindow(mdi_child, SW_HIDE);
3447     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
3448     flush_sequence();
3449
3450     ShowWindow(mdi_child, SW_SHOW);
3451     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
3452
3453     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3454     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3455
3456     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3457     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3458
3459     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3460     ok(!active_child, "wrong active MDI child %p\n", active_child);
3461     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3462
3463     DestroyWindow(mdi_child);
3464     flush_sequence();
3465
3466     trace("creating visible MDI child window\n");
3467     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3468                                 WS_CHILD | WS_VISIBLE,
3469                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3470                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3471     assert(mdi_child);
3472     ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
3473
3474     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3475     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3476
3477     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3478     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3479
3480     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3481     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3482     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3483     flush_sequence();
3484
3485     DestroyWindow(mdi_child);
3486     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3487
3488     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3489     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3490
3491     /* Win2k: MDI client still returns a just destroyed child as active
3492      * Win9x: MDI client returns 0
3493      */
3494     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3495     ok(active_child == mdi_child || /* win2k */
3496        !active_child, /* win9x */
3497        "wrong active MDI child %p\n", active_child);
3498     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3499
3500     flush_sequence();
3501
3502     trace("creating invisible MDI child window\n");
3503     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3504                                 WS_CHILD,
3505                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3506                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3507     assert(mdi_child2);
3508     ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
3509
3510     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
3511     ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
3512
3513     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3514     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3515
3516     /* Win2k: MDI client still returns a just destroyed child as active
3517      * Win9x: MDI client returns mdi_child2
3518      */
3519     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3520     ok(active_child == mdi_child || /* win2k */
3521        active_child == mdi_child2, /* win9x */
3522        "wrong active MDI child %p\n", active_child);
3523     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3524     flush_sequence();
3525
3526     ShowWindow(mdi_child2, SW_MAXIMIZE);
3527     ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
3528
3529     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3530     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3531
3532     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3533     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3534     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3535     flush_sequence();
3536
3537     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3538     ok(GetFocus() == mdi_child2 || /* win2k */
3539        GetFocus() == 0, /* win9x */
3540        "wrong focus window %p\n", GetFocus());
3541
3542     SetFocus(0);
3543     flush_sequence();
3544
3545     ShowWindow(mdi_child2, SW_HIDE);
3546     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3547
3548     ShowWindow(mdi_child2, SW_RESTORE);
3549     ok_sequence(WmRestoreMDIchildInisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
3550     flush_sequence();
3551
3552     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3553     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3554
3555     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3556     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3557     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3558     flush_sequence();
3559
3560     SetFocus(0);
3561     flush_sequence();
3562
3563     ShowWindow(mdi_child2, SW_HIDE);
3564     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3565
3566     ShowWindow(mdi_child2, SW_SHOW);
3567     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
3568
3569     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3570     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3571
3572     ShowWindow(mdi_child2, SW_MAXIMIZE);
3573     ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
3574
3575     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3576     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3577
3578     ShowWindow(mdi_child2, SW_RESTORE);
3579     ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
3580
3581     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3582     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3583
3584     ShowWindow(mdi_child2, SW_MINIMIZE);
3585     ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", TRUE);
3586
3587     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3588     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3589
3590     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3591     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3592     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3593     flush_sequence();
3594
3595     ShowWindow(mdi_child2, SW_RESTORE);
3596     ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", FALSE);
3597
3598     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3599     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3600
3601     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3602     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3603     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3604     flush_sequence();
3605
3606     SetFocus(0);
3607     flush_sequence();
3608
3609     ShowWindow(mdi_child2, SW_HIDE);
3610     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3611
3612     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3613     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3614
3615     DestroyWindow(mdi_child2);
3616     ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
3617
3618     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3619     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3620
3621     /* test for maximized MDI children */
3622     trace("creating maximized visible MDI child window 1\n");
3623     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3624                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3625                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3626                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3627     assert(mdi_child);
3628     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
3629     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3630
3631     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3632     ok(GetFocus() == mdi_child || /* win2k */
3633        GetFocus() == 0, /* win9x */
3634        "wrong focus window %p\n", GetFocus());
3635
3636     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3637     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3638     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3639     flush_sequence();
3640
3641     trace("creating maximized visible MDI child window 2\n");
3642     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3643                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3644                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3645                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3646     assert(mdi_child2);
3647     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3648     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3649     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3650
3651     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3652     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3653
3654     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3655     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3656     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3657     flush_sequence();
3658
3659     trace("destroying maximized visible MDI child window 2\n");
3660     DestroyWindow(mdi_child2);
3661     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3662
3663     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3664
3665     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3666     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3667
3668     /* Win2k: MDI client still returns a just destroyed child as active
3669      * Win9x: MDI client returns 0
3670      */
3671     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3672     ok(active_child == mdi_child2 || /* win2k */
3673        !active_child, /* win9x */
3674        "wrong active MDI child %p\n", active_child);
3675     flush_sequence();
3676
3677     ShowWindow(mdi_child, SW_MAXIMIZE);
3678     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3679     flush_sequence();
3680
3681     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3682     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3683
3684     trace("re-creating maximized visible MDI child window 2\n");
3685     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3686                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3687                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3688                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3689     assert(mdi_child2);
3690     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3691     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3692     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3693
3694     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3695     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3696
3697     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3698     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3699     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3700     flush_sequence();
3701
3702     SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
3703     ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
3704     ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
3705
3706     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3707     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3708     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3709
3710     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3711     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3712     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3713     flush_sequence();
3714
3715     DestroyWindow(mdi_child);
3716     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3717
3718     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3719     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3720
3721     /* Win2k: MDI client still returns a just destroyed child as active
3722      * Win9x: MDI client returns 0
3723      */
3724     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3725     ok(active_child == mdi_child || /* win2k */
3726        !active_child, /* win9x */
3727        "wrong active MDI child %p\n", active_child);
3728     flush_sequence();
3729
3730     trace("creating maximized invisible MDI child window\n");
3731     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3732                                 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
3733                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3734                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3735     assert(mdi_child2);
3736     ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", FALSE);
3737     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3738     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
3739     ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
3740
3741     /* Win2k: MDI client still returns a just destroyed child as active
3742      * Win9x: MDI client returns 0
3743      */
3744     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3745     ok(active_child == mdi_child || /* win2k */
3746        !active_child || active_child == mdi_child2, /* win9x */
3747        "wrong active MDI child %p\n", active_child);
3748     flush_sequence();
3749
3750     trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
3751     ShowWindow(mdi_child2, SW_MAXIMIZE);
3752     ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
3753     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3754     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3755     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3756
3757     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3758     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3759     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3760     flush_sequence();
3761
3762     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3763     flush_sequence();
3764
3765     /* end of test for maximized MDI children */
3766     SetFocus(0);
3767     flush_sequence();
3768     trace("creating maximized visible MDI child window 1(Switch test)\n");
3769     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3770                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3771                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3772                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3773     assert(mdi_child);
3774     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE);
3775     ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n");
3776
3777     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3778     ok(GetFocus() == mdi_child || /* win2k */
3779        GetFocus() == 0, /* win9x */
3780        "wrong focus window %p(Switch test)\n", GetFocus());
3781
3782     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3783     ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3784     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3785     flush_sequence();
3786
3787     trace("creating maximized visible MDI child window 2(Switch test)\n");
3788     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3789                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3790                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3791                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3792     assert(mdi_child2);
3793     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child window (Switch test)", TRUE);
3794
3795     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n");
3796     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized(Switch test)\n");
3797
3798     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3799     ok(GetFocus() == mdi_child2, "wrong focus window %p(Switch test)\n", GetFocus());
3800
3801     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3802     ok(active_child == mdi_child2, "wrong active MDI child %p(Switch test)\n", active_child);
3803     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3804     flush_sequence();
3805
3806     trace("Switch child window.\n");
3807     SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0);
3808     ok_sequence(WmSwitchChild, "Child did not switch correctly", TRUE);
3809     trace("end of test for switch maximized MDI children\n");
3810     flush_sequence();
3811
3812     /* Prepare for switching test of not maximized MDI children  */
3813     ShowWindow( mdi_child, SW_NORMAL );
3814     ok(!IsZoomed(mdi_child), "wrong zoomed state for %p(Switch test)\n", mdi_child);
3815     ok(!IsZoomed(mdi_child2), "wrong zoomed state for %p(Switch test)\n", mdi_child2);
3816     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
3817     ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3818     flush_sequence();
3819
3820     SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child2, 0);
3821     ok_sequence(WmSwitchNotMaximizedChild, "Not maximized child did not switch correctly", FALSE);
3822     trace("end of test for switch not maximized MDI children\n");
3823     flush_sequence();
3824
3825     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3826     flush_sequence();
3827
3828     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3829     flush_sequence();
3830
3831     SetFocus(0);
3832     flush_sequence();
3833     /* end of tests for switch maximized/not maximized MDI children */
3834
3835     mdi_cs.szClass = "MDI_child_Class";
3836     mdi_cs.szTitle = "MDI child";
3837     mdi_cs.hOwner = GetModuleHandleA(0);
3838     mdi_cs.x = 0;
3839     mdi_cs.y = 0;
3840     mdi_cs.cx = CW_USEDEFAULT;
3841     mdi_cs.cy = CW_USEDEFAULT;
3842     mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
3843     mdi_cs.lParam = 0;
3844     mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
3845     ok(mdi_child != 0, "MDI child creation failed\n");
3846     ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
3847
3848     ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
3849
3850     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3851     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3852
3853     ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
3854     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3855     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3856
3857     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3858     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3859     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3860     flush_sequence();
3861
3862     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3863     ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
3864
3865     ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
3866     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3867     ok(!active_child, "wrong active MDI child %p\n", active_child);
3868
3869     SetFocus(0);
3870     flush_sequence();
3871
3872     DestroyWindow(mdi_client);
3873     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3874
3875     /* test maximization of MDI child with invisible parent */
3876     client_cs.hWindowMenu = 0;
3877     mdi_client = CreateWindow("MDI_client_class",
3878                                  NULL,
3879                                  WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
3880                                  0, 0, 660, 430,
3881                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3882     ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
3883
3884     ShowWindow(mdi_client, SW_HIDE);
3885     ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
3886
3887     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3888                                 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
3889                                 0, 0, 650, 440,
3890                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3891     ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
3892
3893     SendMessage(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
3894     ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
3895     zoomed = IsZoomed(mdi_child);
3896     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3897     
3898     ShowWindow(mdi_client, SW_SHOW);
3899     ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
3900
3901     DestroyWindow(mdi_child);
3902     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
3903
3904     /* end of test for maximization of MDI child with invisible parent */
3905
3906     DestroyWindow(mdi_client);
3907     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3908
3909     DestroyWindow(mdi_frame);
3910     ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
3911 }
3912 /************************* End of MDI test **********************************/
3913
3914 static void test_WM_SETREDRAW(HWND hwnd)
3915 {
3916     DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
3917
3918     flush_events();
3919     flush_sequence();
3920
3921     SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3922     ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
3923
3924     ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
3925     ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
3926
3927     flush_sequence();
3928     SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3929     ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
3930
3931     ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
3932     ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
3933
3934     /* restore original WS_VISIBLE state */
3935     SetWindowLongA(hwnd, GWL_STYLE, style);
3936
3937     flush_events();
3938     flush_sequence();
3939 }
3940
3941 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3942 {
3943     struct recvd_message msg;
3944
3945     if (ignore_message( message )) return 0;
3946
3947     switch (message)
3948     {
3949         /* ignore */
3950         case WM_MOUSEMOVE:
3951         case WM_NCMOUSEMOVE:
3952         case WM_NCMOUSELEAVE:
3953         case WM_SETCURSOR:
3954             return 0;
3955         case WM_NCHITTEST:
3956             return HTCLIENT;
3957     }
3958
3959     msg.hwnd = hwnd;
3960     msg.message = message;
3961     msg.flags = sent|wparam|lparam;
3962     msg.wParam = wParam;
3963     msg.lParam = lParam;
3964     msg.descr = "dialog";
3965     add_message(&msg);
3966
3967     if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
3968     if (message == WM_TIMER) EndDialog( hwnd, 0 );
3969     return 0;
3970 }
3971
3972 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
3973 {
3974     DWORD style, exstyle;
3975     INT xmin, xmax;
3976     BOOL ret;
3977
3978     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
3979     style = GetWindowLongA(hwnd, GWL_STYLE);
3980     /* do not be confused by WS_DLGFRAME set */
3981     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
3982
3983     if (clear) ok(style & clear, "style %08x should be set\n", clear);
3984     if (set) ok(!(style & set), "style %08x should not be set\n", set);
3985
3986     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3987     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
3988     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
3989         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
3990     else
3991         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
3992
3993     style = GetWindowLongA(hwnd, GWL_STYLE);
3994     if (set) ok(style & set, "style %08x should be set\n", set);
3995     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
3996
3997     /* a subsequent call should do nothing */
3998     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3999     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
4000     ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4001
4002     xmin = 0xdeadbeef;
4003     xmax = 0xdeadbeef;
4004     ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
4005     ok( ret, "GetScrollRange(%d) error %d\n", ctl, GetLastError());
4006     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4007     ok(xmin == min, "unexpected min scroll value %d\n", xmin);
4008     ok(xmax == max, "unexpected max scroll value %d\n", xmax);
4009 }
4010
4011 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4012 {
4013     DWORD style, exstyle;
4014     SCROLLINFO si;
4015     BOOL ret;
4016
4017     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4018     style = GetWindowLongA(hwnd, GWL_STYLE);
4019     /* do not be confused by WS_DLGFRAME set */
4020     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4021
4022     if (clear) ok(style & clear, "style %08x should be set\n", clear);
4023     if (set) ok(!(style & set), "style %08x should not be set\n", set);
4024
4025     si.cbSize = sizeof(si);
4026     si.fMask = SIF_RANGE;
4027     si.nMin = min;
4028     si.nMax = max;
4029     SetScrollInfo(hwnd, ctl, &si, TRUE);
4030     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4031         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
4032     else
4033         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
4034
4035     style = GetWindowLongA(hwnd, GWL_STYLE);
4036     if (set) ok(style & set, "style %08x should be set\n", set);
4037     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4038
4039     /* a subsequent call should do nothing */
4040     SetScrollInfo(hwnd, ctl, &si, TRUE);
4041     if (style & WS_HSCROLL)
4042         ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4043     else if (style & WS_VSCROLL)
4044         ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4045     else
4046         ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4047
4048     si.fMask = SIF_PAGE;
4049     si.nPage = 5;
4050     SetScrollInfo(hwnd, ctl, &si, FALSE);
4051     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4052
4053     si.fMask = SIF_POS;
4054     si.nPos = max - 1;
4055     SetScrollInfo(hwnd, ctl, &si, FALSE);
4056     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4057
4058     si.fMask = SIF_RANGE;
4059     si.nMin = 0xdeadbeef;
4060     si.nMax = 0xdeadbeef;
4061     ret = GetScrollInfo(hwnd, ctl, &si);
4062     ok( ret, "GetScrollInfo error %d\n", GetLastError());
4063     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4064     ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
4065     ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
4066 }
4067
4068 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
4069 static void test_scroll_messages(HWND hwnd)
4070 {
4071     SCROLLINFO si;
4072     INT min, max;
4073     BOOL ret;
4074
4075     flush_events();
4076     flush_sequence();
4077
4078     min = 0xdeadbeef;
4079     max = 0xdeadbeef;
4080     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4081     ok( ret, "GetScrollRange error %d\n", GetLastError());
4082     if (sequence->message != WmGetScrollRangeSeq[0].message)
4083         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4084     /* values of min and max are undefined */
4085     flush_sequence();
4086
4087     ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
4088     ok( ret, "SetScrollRange error %d\n", GetLastError());
4089     if (sequence->message != WmSetScrollRangeSeq[0].message)
4090         trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4091     flush_sequence();
4092
4093     min = 0xdeadbeef;
4094     max = 0xdeadbeef;
4095     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4096     ok( ret, "GetScrollRange error %d\n", GetLastError());
4097     if (sequence->message != WmGetScrollRangeSeq[0].message)
4098         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4099     /* values of min and max are undefined */
4100     flush_sequence();
4101
4102     si.cbSize = sizeof(si);
4103     si.fMask = SIF_RANGE;
4104     si.nMin = 20;
4105     si.nMax = 160;
4106     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4107     if (sequence->message != WmSetScrollRangeSeq[0].message)
4108         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4109     flush_sequence();
4110
4111     si.fMask = SIF_PAGE;
4112     si.nPage = 10;
4113     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4114     if (sequence->message != WmSetScrollRangeSeq[0].message)
4115         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4116     flush_sequence();
4117
4118     si.fMask = SIF_POS;
4119     si.nPos = 20;
4120     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4121     if (sequence->message != WmSetScrollRangeSeq[0].message)
4122         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4123     flush_sequence();
4124
4125     si.fMask = SIF_RANGE;
4126     si.nMin = 0xdeadbeef;
4127     si.nMax = 0xdeadbeef;
4128     ret = GetScrollInfo(hwnd, SB_CTL, &si);
4129     ok( ret, "GetScrollInfo error %d\n", GetLastError());
4130     if (sequence->message != WmGetScrollInfoSeq[0].message)
4131         trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4132     /* values of min and max are undefined */
4133     flush_sequence();
4134
4135     /* set WS_HSCROLL */
4136     test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4137     /* clear WS_HSCROLL */
4138     test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4139
4140     /* set WS_HSCROLL */
4141     test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4142     /* clear WS_HSCROLL */
4143     test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4144
4145     /* set WS_VSCROLL */
4146     test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4147     /* clear WS_VSCROLL */
4148     test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4149
4150     /* set WS_VSCROLL */
4151     test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4152     /* clear WS_VSCROLL */
4153     test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4154 }
4155
4156 static void test_showwindow(void)
4157 {
4158     HWND hwnd, hchild;
4159     RECT rc;
4160
4161     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4162                            100, 100, 200, 200, 0, 0, 0, NULL);
4163     ok (hwnd != 0, "Failed to create overlapped window\n");
4164     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4165                              0, 0, 10, 10, hwnd, 0, 0, NULL);
4166     ok (hchild != 0, "Failed to create child\n");
4167     flush_sequence();
4168
4169     /* ShowWindow( SW_SHOWNA) for invisible top level window */
4170     trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
4171     ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4172     ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", FALSE);
4173
4174     /* ShowWindow( SW_SHOWNA) for now visible top level window */
4175     trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
4176     ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4177     ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
4178     /* back to invisible */
4179     ShowWindow(hchild, SW_HIDE);
4180     ShowWindow(hwnd, SW_HIDE);
4181     flush_sequence();
4182     /* ShowWindow(SW_SHOWNA) with child and parent invisible */ 
4183     trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
4184     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4185     ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
4186     /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */ 
4187     ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
4188     flush_sequence();
4189     trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
4190     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4191     ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
4192     /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
4193     ShowWindow( hwnd, SW_SHOW);
4194     flush_sequence();
4195     trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
4196     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4197     ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
4198
4199     /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
4200     ShowWindow( hchild, SW_HIDE);
4201     flush_sequence();
4202     trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
4203     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4204     ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
4205
4206     SetCapture(hchild);
4207     ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
4208     DestroyWindow(hchild);
4209     ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
4210
4211     DestroyWindow(hwnd);
4212     flush_sequence();
4213
4214     /* Popup windows */
4215     /* Test 1:
4216      * 1. Create invisible maximized popup window.
4217      * 2. Move and resize it.
4218      * 3. Show it maximized.
4219      */
4220     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4221     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4222                            100, 100, 200, 200, 0, 0, 0, NULL);
4223     ok (hwnd != 0, "Failed to create popup window\n");
4224     ok(IsZoomed(hwnd), "window should be maximized\n");
4225     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4226
4227     GetWindowRect(hwnd, &rc);
4228     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4229         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4230         "Invalid maximized size before ShowWindow (%d,%d)-(%d,%d)\n",
4231         rc.left, rc.top, rc.right, rc.bottom);
4232     /* Reset window's size & position */
4233     SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
4234     ok(IsZoomed(hwnd), "window should be maximized\n");
4235     flush_sequence();
4236
4237     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4238     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4239     ok(IsZoomed(hwnd), "window should be maximized\n");
4240     ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
4241
4242     GetWindowRect(hwnd, &rc);
4243     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4244         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4245         "Invalid maximized size after ShowWindow (%d,%d)-(%d,%d)\n",
4246         rc.left, rc.top, rc.right, rc.bottom);
4247     DestroyWindow(hwnd);
4248     flush_sequence();
4249
4250     /* Test 2:
4251      * 1. Create invisible maximized popup window.
4252      * 2. Show it maximized.
4253      */
4254     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4255     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4256                            100, 100, 200, 200, 0, 0, 0, NULL);
4257     ok (hwnd != 0, "Failed to create popup window\n");
4258     ok(IsZoomed(hwnd), "window should be maximized\n");
4259     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4260
4261     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4262     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4263     ok(IsZoomed(hwnd), "window should be maximized\n");
4264     ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
4265     DestroyWindow(hwnd);
4266     flush_sequence();
4267
4268     /* Test 3:
4269      * 1. Create visible maximized popup window.
4270      */
4271     trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
4272     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
4273                            100, 100, 200, 200, 0, 0, 0, NULL);
4274     ok (hwnd != 0, "Failed to create popup window\n");
4275     ok(IsZoomed(hwnd), "window should be maximized\n");
4276     ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4277     DestroyWindow(hwnd);
4278     flush_sequence();
4279
4280     /* Test 4:
4281      * 1. Create visible popup window.
4282      * 2. Maximize it.
4283      */
4284     trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
4285     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
4286                            100, 100, 200, 200, 0, 0, 0, NULL);
4287     ok (hwnd != 0, "Failed to create popup window\n");
4288     ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
4289     ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE);
4290
4291     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
4292     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4293     ok(IsZoomed(hwnd), "window should be maximized\n");
4294     ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
4295     DestroyWindow(hwnd);
4296     flush_sequence();
4297 }
4298
4299 static void test_sys_menu(void)
4300 {
4301     HWND hwnd;
4302     HMENU hmenu;
4303     UINT state;
4304
4305     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4306                            100, 100, 200, 200, 0, 0, 0, NULL);
4307     ok (hwnd != 0, "Failed to create overlapped window\n");
4308
4309     flush_sequence();
4310
4311     /* test existing window without CS_NOCLOSE style */
4312     hmenu = GetSystemMenu(hwnd, FALSE);
4313     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4314
4315     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4316     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4317     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4318
4319     EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
4320     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4321
4322     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4323     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4324     ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
4325
4326     EnableMenuItem(hmenu, SC_CLOSE, 0);
4327     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4328
4329     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4330     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4331     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4332
4333     /* test whether removing WS_SYSMENU destroys a system menu */
4334     SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
4335     SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4336     flush_sequence();
4337     hmenu = GetSystemMenu(hwnd, FALSE);
4338     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4339
4340     DestroyWindow(hwnd);
4341
4342     /* test new window with CS_NOCLOSE style */
4343     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4344                            100, 100, 200, 200, 0, 0, 0, NULL);
4345     ok (hwnd != 0, "Failed to create overlapped window\n");
4346
4347     hmenu = GetSystemMenu(hwnd, FALSE);
4348     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4349
4350     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4351     ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4352
4353     DestroyWindow(hwnd);
4354
4355     /* test new window without WS_SYSMENU style */
4356     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
4357                            100, 100, 200, 200, 0, 0, 0, NULL);
4358     ok(hwnd != 0, "Failed to create overlapped window\n");
4359
4360     hmenu = GetSystemMenu(hwnd, FALSE);
4361     ok(!hmenu, "GetSystemMenu error %d\n", GetLastError());
4362
4363     DestroyWindow(hwnd);
4364 }
4365
4366 /* For shown WS_OVERLAPPEDWINDOW */
4367 static const struct message WmSetIcon_1[] = {
4368     { WM_SETICON, sent },
4369     { 0x00AE, sent|defwinproc|optional }, /* XP */
4370     { WM_GETTEXT, sent|defwinproc|optional },
4371     { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
4372     { 0 }
4373 };
4374
4375 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
4376 static const struct message WmSetIcon_2[] = {
4377     { WM_SETICON, sent },
4378     { 0 }
4379 };
4380
4381 /* Sending undocumented 0x3B message with wparam = 0x8000000b */
4382 static const struct message WmInitEndSession[] = {
4383     { 0x003B, sent },
4384     { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4385     { 0 }
4386 };
4387
4388 /* Sending undocumented 0x3B message with wparam = 0x0000000b */
4389 static const struct message WmInitEndSession_2[] = {
4390     { 0x003B, sent },
4391     { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4392     { 0 }
4393 };
4394
4395 /* Sending undocumented 0x3B message with wparam = 0x80000008 */
4396 static const struct message WmInitEndSession_3[] = {
4397     { 0x003B, sent },
4398     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4399     { 0 }
4400 };
4401
4402 /* Sending undocumented 0x3B message with wparam = 0x00000008 */
4403 static const struct message WmInitEndSession_4[] = {
4404     { 0x003B, sent },
4405     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4406     { 0 }
4407 };
4408
4409 /* Sending undocumented 0x3B message with wparam = 0x80000001 */
4410 static const struct message WmInitEndSession_5[] = {
4411     { 0x003B, sent },
4412     { WM_ENDSESSION, sent|defwinproc/*|wparam*/|lparam, 1, ENDSESSION_LOGOFF },
4413     { 0 }
4414 };
4415
4416 static const struct message WmOptionalPaint[] = {
4417     { WM_PAINT, sent|optional },
4418     { WM_NCPAINT, sent|beginpaint|optional },
4419     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4420     { WM_ERASEBKGND, sent|beginpaint|optional },
4421     { 0 }
4422 };
4423
4424 static const struct message WmZOrder[] = {
4425     { WM_WINDOWPOSCHANGING, sent|wparam, 0, 0 },
4426     { WM_GETMINMAXINFO, sent|defwinproc|wparam, 0, 0 },
4427     { HCBT_ACTIVATE, hook },
4428     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
4429     { WM_WINDOWPOSCHANGING, sent|wparam, 3, 0 },
4430     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0 },
4431     { WM_GETTEXT, sent|optional },
4432     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
4433     { WM_ACTIVATEAPP, sent|wparam, 1, 0 },
4434     { WM_NCACTIVATE, sent|lparam, 1, 0 },
4435     { WM_GETTEXT, sent|defwinproc|optional },
4436     { WM_GETTEXT, sent|defwinproc|optional },
4437     { WM_ACTIVATE, sent|wparam|lparam, 1, 0 },
4438     { HCBT_SETFOCUS, hook },
4439     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
4440     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4441     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
4442     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
4443     { WM_GETTEXT, sent|optional },
4444     { WM_NCCALCSIZE, sent|optional },
4445     { 0 }
4446 };
4447
4448 static void test_MsgWaitForMultipleObjects(HWND hwnd)
4449 {
4450     DWORD ret;
4451     MSG msg;
4452
4453     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4454     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4455
4456     PostMessageA(hwnd, WM_USER, 0, 0);
4457
4458     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4459     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4460
4461     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4462     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4463
4464     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4465     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4466
4467     PostMessageA(hwnd, WM_USER, 0, 0);
4468
4469     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4470     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4471
4472     ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
4473     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4474
4475     /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
4476     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4477     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4478
4479     PostMessageA(hwnd, WM_USER, 0, 0);
4480
4481     /* new incoming message causes it to become signaled again */
4482     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4483     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4484
4485     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4486     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4487     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4488     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4489 }
4490
4491 /* test if we receive the right sequence of messages */
4492 static void test_messages(void)
4493 {
4494     HWND hwnd, hparent, hchild;
4495     HWND hchild2, hbutton;
4496     HMENU hmenu;
4497     MSG msg;
4498     LRESULT res;
4499
4500     flush_sequence();
4501
4502     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4503                            100, 100, 200, 200, 0, 0, 0, NULL);
4504     ok (hwnd != 0, "Failed to create overlapped window\n");
4505     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4506
4507     /* test ShowWindow(SW_HIDE) on a newly created invisible window */
4508     ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
4509     ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
4510
4511     /* test WM_SETREDRAW on a not visible top level window */
4512     test_WM_SETREDRAW(hwnd);
4513
4514     SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4515     flush_events();
4516     ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
4517     ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
4518
4519     ok(GetActiveWindow() == hwnd, "window should be active\n");
4520     ok(GetFocus() == hwnd, "window should have input focus\n");
4521     ShowWindow(hwnd, SW_HIDE);
4522     flush_events();
4523     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
4524
4525     ShowWindow(hwnd, SW_SHOW);
4526     flush_events();
4527     ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
4528
4529     ShowWindow(hwnd, SW_HIDE);
4530     flush_events();
4531     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
4532
4533     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4534     flush_events();
4535     ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
4536     flush_sequence();
4537
4538     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZE)
4539     {
4540         ShowWindow(hwnd, SW_RESTORE);
4541         flush_events();
4542         ok_sequence(WmShowRestoreMaxOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
4543         flush_sequence();
4544     }
4545
4546     ShowWindow(hwnd, SW_MINIMIZE);
4547     flush_events();
4548     ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE);
4549     flush_sequence();
4550
4551     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE)
4552     {
4553         ShowWindow(hwnd, SW_RESTORE);
4554         flush_events();
4555         ok_sequence(WmShowRestoreMinOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
4556         flush_sequence();
4557     }
4558
4559     ShowWindow(hwnd, SW_SHOW);
4560     flush_events();
4561     ok_sequence(WmOptionalPaint, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
4562
4563     SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4564     ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
4565     ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
4566     ok(GetActiveWindow() == hwnd, "window should still be active\n");
4567
4568     /* test WM_SETREDRAW on a visible top level window */
4569     ShowWindow(hwnd, SW_SHOW);
4570     flush_events();
4571     test_WM_SETREDRAW(hwnd);
4572
4573     trace("testing scroll APIs on a visible top level window %p\n", hwnd);
4574     test_scroll_messages(hwnd);
4575
4576     /* test resizing and moving */
4577     SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
4578     ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
4579     flush_events();
4580     flush_sequence();
4581     SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
4582     ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
4583     flush_events();
4584     flush_sequence();
4585     SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER|SWP_NOACTIVATE );
4586     ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
4587     flush_events();
4588     flush_sequence();
4589
4590     /* popups don't get WM_GETMINMAXINFO */
4591     SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
4592     SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4593     flush_sequence();
4594     SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
4595     ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
4596
4597     DestroyWindow(hwnd);
4598     ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
4599
4600     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4601                               100, 100, 200, 200, 0, 0, 0, NULL);
4602     ok (hparent != 0, "Failed to create parent window\n");
4603     flush_sequence();
4604
4605     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
4606                              0, 0, 10, 10, hparent, 0, 0, NULL);
4607     ok (hchild != 0, "Failed to create child window\n");
4608     ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
4609     DestroyWindow(hchild);
4610     flush_sequence();
4611
4612     /* visible child window with a caption */
4613     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
4614                              WS_CHILD | WS_VISIBLE | WS_CAPTION,
4615                              0, 0, 10, 10, hparent, 0, 0, NULL);
4616     ok (hchild != 0, "Failed to create child window\n");
4617     ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
4618
4619     trace("testing scroll APIs on a visible child window %p\n", hchild);
4620     test_scroll_messages(hchild);
4621
4622     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4623     ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
4624
4625     DestroyWindow(hchild);
4626     flush_sequence();
4627
4628     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4629                              0, 0, 10, 10, hparent, 0, 0, NULL);
4630     ok (hchild != 0, "Failed to create child window\n");
4631     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4632     
4633     hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
4634                                100, 100, 50, 50, hparent, 0, 0, NULL);
4635     ok (hchild2 != 0, "Failed to create child2 window\n");
4636     flush_sequence();
4637
4638     hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
4639                               0, 100, 50, 50, hchild, 0, 0, NULL);
4640     ok (hbutton != 0, "Failed to create button window\n");
4641
4642     /* test WM_SETREDRAW on a not visible child window */
4643     test_WM_SETREDRAW(hchild);
4644
4645     ShowWindow(hchild, SW_SHOW);
4646     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4647
4648     /* check parent messages too */
4649     log_all_parent_messages++;
4650     ShowWindow(hchild, SW_HIDE);
4651     ok_sequence(WmHideChildSeq2, "ShowWindow(SW_HIDE):child", FALSE);
4652     log_all_parent_messages--;
4653
4654     ShowWindow(hchild, SW_SHOW);
4655     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4656
4657     ShowWindow(hchild, SW_HIDE);
4658     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
4659
4660     ShowWindow(hchild, SW_SHOW);
4661     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4662
4663     /* test WM_SETREDRAW on a visible child window */
4664     test_WM_SETREDRAW(hchild);
4665
4666     log_all_parent_messages++;
4667     MoveWindow(hchild, 10, 10, 20, 20, TRUE);
4668     ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
4669     log_all_parent_messages--;
4670
4671     ShowWindow(hchild, SW_HIDE);
4672     flush_sequence();
4673     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4674     ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
4675
4676     ShowWindow(hchild, SW_HIDE);
4677     flush_sequence();
4678     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
4679     ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
4680
4681     /* DestroyWindow sequence below expects that a child has focus */
4682     SetFocus(hchild);
4683     flush_sequence();
4684
4685     DestroyWindow(hchild);
4686     ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
4687     DestroyWindow(hchild2);
4688     DestroyWindow(hbutton);
4689
4690     flush_sequence();
4691     hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
4692                              0, 0, 100, 100, hparent, 0, 0, NULL);
4693     ok (hchild != 0, "Failed to create child popup window\n");
4694     ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
4695     DestroyWindow(hchild);
4696
4697     /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
4698     flush_sequence();
4699     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
4700                              0, 0, 100, 100, hparent, 0, 0, NULL);
4701     ok (hchild != 0, "Failed to create popup window\n");
4702     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4703     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4704     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4705     flush_sequence();
4706     ShowWindow(hchild, SW_SHOW);
4707     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4708     flush_sequence();
4709     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4710     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4711     flush_sequence();
4712     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4713     ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
4714     DestroyWindow(hchild);
4715
4716     /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
4717      * changes nothing in message sequences.
4718      */
4719     flush_sequence();
4720     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
4721                              0, 0, 100, 100, hparent, 0, 0, NULL);
4722     ok (hchild != 0, "Failed to create popup window\n");
4723     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4724     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4725     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4726     flush_sequence();
4727     ShowWindow(hchild, SW_SHOW);
4728     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4729     flush_sequence();
4730     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4731     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4732     DestroyWindow(hchild);
4733
4734     flush_sequence();
4735     hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
4736                            0, 0, 100, 100, hparent, 0, 0, NULL);
4737     ok(hwnd != 0, "Failed to create custom dialog window\n");
4738     ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
4739
4740     if(0) {
4741     trace("testing scroll APIs on a visible dialog %p\n", hwnd);
4742     test_scroll_messages(hwnd);
4743     }
4744
4745     flush_sequence();
4746
4747     test_def_id = 1;
4748     SendMessage(hwnd, WM_NULL, 0, 0);
4749
4750     flush_sequence();
4751     after_end_dialog = 1;
4752     EndDialog( hwnd, 0 );
4753     ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
4754
4755     DestroyWindow(hwnd);
4756     after_end_dialog = 0;
4757     test_def_id = 0;
4758
4759     hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP,
4760                            0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
4761     ok(hwnd != 0, "Failed to create custom dialog window\n");
4762     flush_sequence();
4763     trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
4764     ShowWindow(hwnd, SW_SHOW);
4765     ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
4766     DestroyWindow(hwnd);
4767
4768     flush_sequence();
4769     DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
4770     ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
4771
4772     DestroyWindow(hparent);
4773     flush_sequence();
4774
4775     /* Message sequence for SetMenu */
4776     ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a window without a menu\n");
4777     ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
4778
4779     hmenu = CreateMenu();
4780     ok (hmenu != 0, "Failed to create menu\n");
4781     ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
4782     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4783                            100, 100, 200, 200, 0, hmenu, 0, NULL);
4784     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4785     ok (SetMenu(hwnd, 0), "SetMenu\n");
4786     ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
4787     ok (SetMenu(hwnd, 0), "SetMenu\n");
4788     ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
4789     ShowWindow(hwnd, SW_SHOW);
4790     UpdateWindow( hwnd );
4791     flush_events();
4792     flush_sequence();
4793     ok (SetMenu(hwnd, 0), "SetMenu\n");
4794     ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
4795     ok (SetMenu(hwnd, hmenu), "SetMenu\n");
4796     ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
4797
4798     UpdateWindow( hwnd );
4799     flush_events();
4800     flush_sequence();
4801     ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
4802     flush_events();
4803     ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
4804
4805     DestroyWindow(hwnd);
4806     flush_sequence();
4807
4808     /* Message sequence for EnableWindow */
4809     hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4810                               100, 100, 200, 200, 0, 0, 0, NULL);
4811     ok (hparent != 0, "Failed to create parent window\n");
4812     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
4813                              0, 0, 10, 10, hparent, 0, 0, NULL);
4814     ok (hchild != 0, "Failed to create child window\n");
4815
4816     SetFocus(hchild);
4817     flush_events();
4818     flush_sequence();
4819
4820     EnableWindow(hparent, FALSE);
4821     ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
4822
4823     EnableWindow(hparent, TRUE);
4824     ok_sequence(WmEnableWindowSeq_2, "EnableWindow(TRUE)", FALSE);
4825
4826     flush_events();
4827     flush_sequence();
4828
4829     test_MsgWaitForMultipleObjects(hparent);
4830
4831     /* the following test causes an exception in user.exe under win9x */
4832     if (!PostMessageW( hparent, WM_USER, 0, 0 ))
4833     {
4834         DestroyWindow(hparent);
4835         flush_sequence();
4836         return;
4837     }
4838     PostMessageW( hparent, WM_USER+1, 0, 0 );
4839     /* PeekMessage(NULL) fails, but still removes the message */
4840     SetLastError(0xdeadbeef);
4841     ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
4842     ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
4843         GetLastError() == 0xdeadbeef, /* NT4 */
4844         "last error is %d\n", GetLastError() );
4845     ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
4846     ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
4847
4848     DestroyWindow(hchild);
4849     DestroyWindow(hparent);
4850     flush_sequence();
4851
4852     /* Message sequences for WM_SETICON */
4853     trace("testing WM_SETICON\n");
4854     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4855                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4856                            NULL, NULL, 0);
4857     ShowWindow(hwnd, SW_SHOW);
4858     UpdateWindow(hwnd);
4859     flush_events();
4860     flush_sequence();
4861     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4862     ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
4863
4864     ShowWindow(hwnd, SW_HIDE);
4865     flush_events();
4866     flush_sequence();
4867     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4868     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window with caption", FALSE);
4869     DestroyWindow(hwnd);
4870     flush_sequence();
4871
4872     hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
4873                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4874                            NULL, NULL, 0);
4875     ShowWindow(hwnd, SW_SHOW);
4876     UpdateWindow(hwnd);
4877     flush_events();
4878     flush_sequence();
4879     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4880     ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
4881
4882     ShowWindow(hwnd, SW_HIDE);
4883     flush_events();
4884     flush_sequence();
4885     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4886     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
4887
4888     flush_sequence();
4889     res = SendMessage(hwnd, 0x3B, 0x8000000b, 0);
4890     if (!res)
4891     {
4892         todo_wine win_skip( "Message 0x3b not supported\n" );
4893         goto done;
4894     }
4895     ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE);
4896     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %ld\n", res);
4897     res = SendMessage(hwnd, 0x3B, 0x0000000b, 0);
4898     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE);
4899     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %ld\n", res);
4900     res = SendMessage(hwnd, 0x3B, 0x0000000f, 0);
4901     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE);
4902     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %ld\n", res);
4903
4904     flush_sequence();
4905     res = SendMessage(hwnd, 0x3B, 0x80000008, 0);
4906     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE);
4907     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %ld\n", res);
4908     res = SendMessage(hwnd, 0x3B, 0x00000008, 0);
4909     ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE);
4910     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %ld\n", res);
4911
4912     res = SendMessage(hwnd, 0x3B, 0x80000004, 0);
4913     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE);
4914     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %ld\n", res);
4915
4916     res = SendMessage(hwnd, 0x3B, 0x80000001, 0);
4917     ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE);
4918     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %ld\n", res);
4919
4920 done:
4921     DestroyWindow(hwnd);
4922     flush_sequence();
4923 }
4924
4925 static void test_setwindowpos(void)
4926 {
4927     HWND hwnd;
4928     RECT rc;
4929     LRESULT res;
4930     const INT winX = 100;
4931     const INT winY = 100;
4932     const INT sysX = GetSystemMetrics(SM_CXMINTRACK);
4933
4934     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
4935                            0, 0, winX, winY, 0,
4936                            NULL, NULL, 0);
4937
4938     GetWindowRect(hwnd, &rc);
4939     expect(sysX, rc.right);
4940     expect(winY, rc.bottom);
4941
4942     flush_events();
4943     flush_sequence();
4944     res = SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, winX, winY, 0);
4945     ok_sequence(WmZOrder, "Z-Order", TRUE);
4946     ok(res == TRUE, "SetWindowPos expected TRUE, got %ld\n", res);
4947
4948     GetWindowRect(hwnd, &rc);
4949     expect(sysX, rc.right);
4950     expect(winY, rc.bottom);
4951     DestroyWindow(hwnd);
4952 }
4953
4954 static void invisible_parent_tests(void)
4955 {
4956     HWND hparent, hchild;
4957
4958     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
4959                               100, 100, 200, 200, 0, 0, 0, NULL);
4960     ok (hparent != 0, "Failed to create parent window\n");
4961     flush_sequence();
4962
4963     /* test showing child with hidden parent */
4964
4965     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4966                              0, 0, 10, 10, hparent, 0, 0, NULL);
4967     ok (hchild != 0, "Failed to create child window\n");
4968     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4969
4970     ShowWindow( hchild, SW_MINIMIZE );
4971     ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4972     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4973     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4974
4975     /* repeat */
4976     flush_events();
4977     flush_sequence();
4978     ShowWindow( hchild, SW_MINIMIZE );
4979     ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4980
4981     DestroyWindow(hchild);
4982     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4983                              0, 0, 10, 10, hparent, 0, 0, NULL);
4984     flush_sequence();
4985
4986     ShowWindow( hchild, SW_MAXIMIZE );
4987     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
4988     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4989     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4990
4991     /* repeat */
4992     flush_events();
4993     flush_sequence();
4994     ShowWindow( hchild, SW_MAXIMIZE );
4995     ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
4996
4997     DestroyWindow(hchild);
4998     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4999                              0, 0, 10, 10, hparent, 0, 0, NULL);
5000     flush_sequence();
5001
5002     ShowWindow( hchild, SW_RESTORE );
5003     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
5004     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5005     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5006
5007     DestroyWindow(hchild);
5008     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5009                              0, 0, 10, 10, hparent, 0, 0, NULL);
5010     flush_sequence();
5011
5012     ShowWindow( hchild, SW_SHOWMINIMIZED );
5013     ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
5014     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5015     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5016
5017     /* repeat */
5018     flush_events();
5019     flush_sequence();
5020     ShowWindow( hchild, SW_SHOWMINIMIZED );
5021     ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
5022
5023     DestroyWindow(hchild);
5024     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5025                              0, 0, 10, 10, hparent, 0, 0, NULL);
5026     flush_sequence();
5027
5028     /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
5029     ShowWindow( hchild, SW_SHOWMAXIMIZED );
5030     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
5031     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5032     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5033
5034     DestroyWindow(hchild);
5035     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5036                              0, 0, 10, 10, hparent, 0, 0, NULL);
5037     flush_sequence();
5038
5039     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5040     ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5041     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5042     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5043
5044     /* repeat */
5045     flush_events();
5046     flush_sequence();
5047     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5048     ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5049
5050     DestroyWindow(hchild);
5051     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5052                              0, 0, 10, 10, hparent, 0, 0, NULL);
5053     flush_sequence();
5054
5055     /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
5056     ShowWindow( hchild, SW_FORCEMINIMIZE );
5057     ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
5058 todo_wine {
5059     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5060 }
5061     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5062
5063     DestroyWindow(hchild);
5064     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5065                              0, 0, 10, 10, hparent, 0, 0, NULL);
5066     flush_sequence();
5067
5068     ShowWindow( hchild, SW_SHOWNA );
5069     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5070     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5071     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5072
5073     /* repeat */
5074     flush_events();
5075     flush_sequence();
5076     ShowWindow( hchild, SW_SHOWNA );
5077     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5078
5079     DestroyWindow(hchild);
5080     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5081                              0, 0, 10, 10, hparent, 0, 0, NULL);
5082     flush_sequence();
5083
5084     ShowWindow( hchild, SW_SHOW );
5085     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5086     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5087     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5088
5089     /* repeat */
5090     flush_events();
5091     flush_sequence();
5092     ShowWindow( hchild, SW_SHOW );
5093     ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5094
5095     ShowWindow( hchild, SW_HIDE );
5096     ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
5097     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5098     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5099
5100     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5101     ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
5102     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5103     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5104
5105     SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5106     ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
5107     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
5108     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5109
5110     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5111     flush_sequence();
5112     DestroyWindow(hchild);
5113     ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
5114
5115     DestroyWindow(hparent);
5116     flush_sequence();
5117 }
5118
5119 /****************** button message test *************************/
5120 #define ID_BUTTON 0x000e
5121
5122 static const struct message WmSetFocusButtonSeq[] =
5123 {
5124     { HCBT_SETFOCUS, hook },
5125     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5126     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5127     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5128     { WM_SETFOCUS, sent|wparam, 0 },
5129     { WM_CTLCOLORBTN, sent|parent },
5130     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5131     { WM_APP, sent|wparam|lparam, 0, 0 },
5132     { 0 }
5133 };
5134 static const struct message WmKillFocusButtonSeq[] =
5135 {
5136     { HCBT_SETFOCUS, hook },
5137     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5138     { WM_KILLFOCUS, sent|wparam, 0 },
5139     { WM_CTLCOLORBTN, sent|parent },
5140     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5141     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5142     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5143     { WM_APP, sent|wparam|lparam, 0, 0 },
5144     { WM_PAINT, sent },
5145     { WM_CTLCOLORBTN, sent|parent },
5146     { 0 }
5147 };
5148 static const struct message WmSetFocusStaticSeq[] =
5149 {
5150     { HCBT_SETFOCUS, hook },
5151     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5152     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5153     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5154     { WM_SETFOCUS, sent|wparam, 0 },
5155     { WM_CTLCOLORSTATIC, sent|parent },
5156     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5157     { WM_COMMAND, sent|wparam|parent|optional, MAKEWPARAM(ID_BUTTON, BN_CLICKED) }, /* radio button */
5158     { WM_APP, sent|wparam|lparam, 0, 0 },
5159     { 0 }
5160 };
5161 static const struct message WmKillFocusStaticSeq[] =
5162 {
5163     { HCBT_SETFOCUS, hook },
5164     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5165     { WM_KILLFOCUS, sent|wparam, 0 },
5166     { WM_CTLCOLORSTATIC, sent|parent },
5167     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5168     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5169     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5170     { WM_APP, sent|wparam|lparam, 0, 0 },
5171     { WM_PAINT, sent },
5172     { WM_CTLCOLORSTATIC, sent|parent },
5173     { 0 }
5174 };
5175 static const struct message WmSetFocusOwnerdrawSeq[] =
5176 {
5177     { HCBT_SETFOCUS, hook },
5178     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5179     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5180     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5181     { WM_SETFOCUS, sent|wparam, 0 },
5182     { WM_CTLCOLORBTN, sent|parent },
5183     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x001040e4 },
5184     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5185     { WM_APP, sent|wparam|lparam, 0, 0 },
5186     { 0 }
5187 };
5188 static const struct message WmKillFocusOwnerdrawSeq[] =
5189 {
5190     { HCBT_SETFOCUS, hook },
5191     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5192     { WM_KILLFOCUS, sent|wparam, 0 },
5193     { WM_CTLCOLORBTN, sent|parent },
5194     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000040e4 },
5195     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5196     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5197     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5198     { WM_APP, sent|wparam|lparam, 0, 0 },
5199     { WM_PAINT, sent },
5200     { WM_CTLCOLORBTN, sent|parent },
5201     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
5202     { 0 }
5203 };
5204 static const struct message WmLButtonDownSeq[] =
5205 {
5206     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
5207     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5208     { HCBT_SETFOCUS, hook },
5209     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
5210     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5211     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5212     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
5213     { WM_CTLCOLORBTN, sent|defwinproc },
5214     { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
5215     { WM_CTLCOLORBTN, sent|defwinproc },
5216     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5217     { 0 }
5218 };
5219 static const struct message WmLButtonUpSeq[] =
5220 {
5221     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
5222     { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
5223     { WM_CTLCOLORBTN, sent|defwinproc },
5224     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5225     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
5226     { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
5227     { 0 }
5228 };
5229 static const struct message WmSetFontButtonSeq[] =
5230 {
5231     { WM_SETFONT, sent },
5232     { WM_PAINT, sent },
5233     { WM_ERASEBKGND, sent|defwinproc|optional },
5234     { WM_CTLCOLORBTN, sent|defwinproc },
5235     { 0 }
5236 };
5237 static const struct message WmSetStyleButtonSeq[] =
5238 {
5239     { BM_SETSTYLE, sent },
5240     { WM_APP, sent|wparam|lparam, 0, 0 },
5241     { WM_PAINT, sent },
5242     { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
5243     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5244     { WM_CTLCOLORBTN, sent|parent },
5245     { 0 }
5246 };
5247 static const struct message WmSetStyleStaticSeq[] =
5248 {
5249     { BM_SETSTYLE, sent },
5250     { WM_APP, sent|wparam|lparam, 0, 0 },
5251     { WM_PAINT, sent },
5252     { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
5253     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5254     { WM_CTLCOLORSTATIC, sent|parent },
5255     { 0 }
5256 };
5257 static const struct message WmSetStyleUserSeq[] =
5258 {
5259     { BM_SETSTYLE, sent },
5260     { WM_APP, sent|wparam|lparam, 0, 0 },
5261     { WM_PAINT, sent },
5262     { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
5263     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5264     { WM_CTLCOLORBTN, sent|parent },
5265     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_PAINT) },
5266     { 0 }
5267 };
5268 static const struct message WmSetStyleOwnerdrawSeq[] =
5269 {
5270     { BM_SETSTYLE, sent },
5271     { WM_APP, sent|wparam|lparam, 0, 0 },
5272     { WM_PAINT, sent },
5273     { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
5274     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5275     { WM_CTLCOLORBTN, sent|parent },
5276     { WM_CTLCOLORBTN, sent|parent|optional }, /* Win9x doesn't send it */
5277     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
5278     { 0 }
5279 };
5280 static const struct message WmSetStateButtonSeq[] =
5281 {
5282     { BM_SETSTATE, sent },
5283     { WM_CTLCOLORBTN, sent|parent },
5284     { WM_APP, sent|wparam|lparam, 0, 0 },
5285     { 0 }
5286 };
5287 static const struct message WmSetStateStaticSeq[] =
5288 {
5289     { BM_SETSTATE, sent },
5290     { WM_CTLCOLORSTATIC, sent|parent },
5291     { WM_APP, sent|wparam|lparam, 0, 0 },
5292     { 0 }
5293 };
5294 static const struct message WmSetStateUserSeq[] =
5295 {
5296     { BM_SETSTATE, sent },
5297     { WM_CTLCOLORBTN, sent|parent },
5298     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_HILITE) },
5299     { WM_APP, sent|wparam|lparam, 0, 0 },
5300     { 0 }
5301 };
5302 static const struct message WmSetStateOwnerdrawSeq[] =
5303 {
5304     { BM_SETSTATE, sent },
5305     { WM_CTLCOLORBTN, sent|parent },
5306     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000120e4 },
5307     { WM_APP, sent|wparam|lparam, 0, 0 },
5308     { 0 }
5309 };
5310 static const struct message WmClearStateButtonSeq[] =
5311 {
5312     { BM_SETSTATE, sent },
5313     { WM_CTLCOLORBTN, sent|parent },
5314     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_UNHILITE) },
5315     { WM_APP, sent|wparam|lparam, 0, 0 },
5316     { 0 }
5317 };
5318 static const struct message WmClearStateOwnerdrawSeq[] =
5319 {
5320     { BM_SETSTATE, sent },
5321     { WM_CTLCOLORBTN, sent|parent },
5322     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000020e4 },
5323     { WM_APP, sent|wparam|lparam, 0, 0 },
5324     { 0 }
5325 };
5326 static const struct message WmSetCheckIgnoredSeq[] =
5327 {
5328     { BM_SETCHECK, sent },
5329     { WM_APP, sent|wparam|lparam, 0, 0 },
5330     { 0 }
5331 };
5332 static const struct message WmSetCheckStaticSeq[] =
5333 {
5334     { BM_SETCHECK, sent },
5335     { WM_CTLCOLORSTATIC, sent|parent },
5336     { WM_APP, sent|wparam|lparam, 0, 0 },
5337     { 0 }
5338 };
5339
5340 static WNDPROC old_button_proc;
5341
5342 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5343 {
5344     static LONG defwndproc_counter = 0;
5345     LRESULT ret;
5346     struct recvd_message msg;
5347
5348     if (ignore_message( message )) return 0;
5349
5350     switch (message)
5351     {
5352     case WM_SYNCPAINT:
5353         break;
5354     case BM_SETSTATE:
5355         if (GetCapture())
5356             ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
5357         /* fall through */
5358     default:
5359         msg.hwnd = hwnd;
5360         msg.message = message;
5361         msg.flags = sent|wparam|lparam;
5362         if (defwndproc_counter) msg.flags |= defwinproc;
5363         msg.wParam = wParam;
5364         msg.lParam = lParam;
5365         msg.descr = "button";
5366         add_message(&msg);
5367     }
5368
5369     defwndproc_counter++;
5370     ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
5371     defwndproc_counter--;
5372
5373     return ret;
5374 }
5375
5376 static void subclass_button(void)
5377 {
5378     WNDCLASSA cls;
5379
5380     if (!GetClassInfoA(0, "button", &cls)) assert(0);
5381
5382     old_button_proc = cls.lpfnWndProc;
5383
5384     cls.hInstance = GetModuleHandle(0);
5385     cls.lpfnWndProc = button_hook_proc;
5386     cls.lpszClassName = "my_button_class";
5387     UnregisterClass(cls.lpszClassName, cls.hInstance);
5388     if (!RegisterClassA(&cls)) assert(0);
5389 }
5390
5391 static void test_button_messages(void)
5392 {
5393     static const struct
5394     {
5395         DWORD style;
5396         DWORD dlg_code;
5397         const struct message *setfocus;
5398         const struct message *killfocus;
5399         const struct message *setstyle;
5400         const struct message *setstate;
5401         const struct message *clearstate;
5402         const struct message *setcheck;
5403     } button[] = {
5404         { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
5405           WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
5406           WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq },
5407         { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
5408           WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
5409           WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq },
5410         { BS_CHECKBOX, DLGC_BUTTON,
5411           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5412           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5413         { BS_AUTOCHECKBOX, DLGC_BUTTON,
5414           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5415           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5416         { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
5417           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5418           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5419         { BS_3STATE, DLGC_BUTTON,
5420           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5421           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5422         { BS_AUTO3STATE, DLGC_BUTTON,
5423           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5424           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5425         { BS_GROUPBOX, DLGC_STATIC,
5426           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5427           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckIgnoredSeq },
5428         { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
5429           WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleUserSeq,
5430           WmSetStateUserSeq, WmClearStateButtonSeq, WmSetCheckIgnoredSeq },
5431         { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
5432           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5433           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5434         { BS_OWNERDRAW, DLGC_BUTTON,
5435           WmSetFocusOwnerdrawSeq, WmKillFocusOwnerdrawSeq, WmSetStyleOwnerdrawSeq,
5436           WmSetStateOwnerdrawSeq, WmClearStateOwnerdrawSeq, WmSetCheckIgnoredSeq },
5437     };
5438     unsigned int i;
5439     HWND hwnd, parent;
5440     DWORD dlg_code;
5441     HFONT zfont;
5442
5443     /* selection with VK_SPACE should capture button window */
5444     hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP,
5445                            0, 0, 50, 14, 0, 0, 0, NULL);
5446     ok(hwnd != 0, "Failed to create button window\n");
5447     ReleaseCapture();
5448     SetFocus(hwnd);
5449     SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
5450     ok(GetCapture() == hwnd, "Should be captured on VK_SPACE WM_KEYDOWN\n");
5451     SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
5452     DestroyWindow(hwnd);
5453
5454     subclass_button();
5455
5456     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5457                              100, 100, 200, 200, 0, 0, 0, NULL);
5458     ok(parent != 0, "Failed to create parent window\n");
5459
5460     for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
5461     {
5462         MSG msg;
5463         DWORD style, state;
5464
5465         trace("button style %08x\n", button[i].style);
5466
5467         hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_CHILD | BS_NOTIFY,
5468                                0, 0, 50, 14, parent, (HMENU)ID_BUTTON, 0, NULL);
5469         ok(hwnd != 0, "Failed to create button window\n");
5470
5471         style = GetWindowLongA(hwnd, GWL_STYLE);
5472         style &= ~(WS_CHILD | BS_NOTIFY);
5473         /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
5474         if (button[i].style == BS_USERBUTTON)
5475             ok(style == BS_PUSHBUTTON, "expected style BS_PUSHBUTTON got %x\n", style);
5476         else
5477             ok(style == button[i].style, "expected style %x got %x\n", button[i].style, style);
5478
5479         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
5480         ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
5481
5482         ShowWindow(hwnd, SW_SHOW);
5483         UpdateWindow(hwnd);
5484         SetFocus(0);
5485         flush_events();
5486         SetFocus(0);
5487         flush_sequence();
5488
5489         log_all_parent_messages++;
5490
5491         ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
5492         SetFocus(hwnd);
5493         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5494         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5495         ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
5496
5497         SetFocus(0);
5498         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5499         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5500         ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
5501
5502         ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
5503
5504         SendMessage(hwnd, BM_SETSTYLE, button[i].style | BS_BOTTOM, TRUE);
5505         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5506         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5507         ok_sequence(button[i].setstyle, "BM_SETSTYLE on a button", FALSE);
5508
5509         style = GetWindowLongA(hwnd, GWL_STYLE);
5510         style &= ~(WS_VISIBLE | WS_CHILD | BS_NOTIFY);
5511         /* XP doesn't turn a BS_USERBUTTON into BS_PUSHBUTTON here! */
5512         ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5513
5514         state = SendMessage(hwnd, BM_GETSTATE, 0, 0);
5515         ok(state == 0, "expected state 0, got %04x\n", state);
5516
5517         flush_sequence();
5518
5519         SendMessage(hwnd, BM_SETSTATE, TRUE, 0);
5520         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5521         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5522         ok_sequence(button[i].setstate, "BM_SETSTATE/TRUE on a button", FALSE);
5523
5524         state = SendMessage(hwnd, BM_GETSTATE, 0, 0);
5525         ok(state == 0x0004, "expected state 0x0004, got %04x\n", state);
5526
5527         style = GetWindowLongA(hwnd, GWL_STYLE);
5528         style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
5529         ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5530
5531         flush_sequence();
5532
5533         SendMessage(hwnd, BM_SETSTATE, FALSE, 0);
5534         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5535         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5536         ok_sequence(button[i].clearstate, "BM_SETSTATE/FALSE on a button", FALSE);
5537
5538         state = SendMessage(hwnd, BM_GETSTATE, 0, 0);
5539         ok(state == 0, "expected state 0, got %04x\n", state);
5540
5541         style = GetWindowLongA(hwnd, GWL_STYLE);
5542         style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
5543         ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5544
5545         state = SendMessage(hwnd, BM_GETCHECK, 0, 0);
5546         ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
5547
5548         flush_sequence();
5549
5550         SendMessage(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
5551         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5552         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5553         ok_sequence(WmSetCheckIgnoredSeq, "BM_SETCHECK on a button", FALSE);
5554
5555         state = SendMessage(hwnd, BM_GETCHECK, 0, 0);
5556         ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
5557
5558         style = GetWindowLongA(hwnd, GWL_STYLE);
5559         style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
5560         ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5561
5562         flush_sequence();
5563
5564         SendMessage(hwnd, BM_SETCHECK, BST_CHECKED, 0);
5565         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5566         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5567         ok_sequence(button[i].setcheck, "BM_SETCHECK on a button", FALSE);
5568
5569         state = SendMessage(hwnd, BM_GETCHECK, 0, 0);
5570         if (button[i].style == BS_PUSHBUTTON ||
5571             button[i].style == BS_DEFPUSHBUTTON ||
5572             button[i].style == BS_GROUPBOX ||
5573             button[i].style == BS_USERBUTTON ||
5574             button[i].style == BS_OWNERDRAW)
5575             ok(state == BST_UNCHECKED, "expected check 0, got %04x\n", state);
5576         else
5577             ok(state == BST_CHECKED, "expected check 1, got %04x\n", state);
5578
5579         style = GetWindowLongA(hwnd, GWL_STYLE);
5580         style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
5581         if (button[i].style == BS_RADIOBUTTON ||
5582             button[i].style == BS_AUTORADIOBUTTON)
5583             ok(style == (button[i].style | WS_TABSTOP), "expected style %04x | WS_TABSTOP got %04x\n", button[i].style, style);
5584         else
5585             ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5586
5587         log_all_parent_messages--;
5588
5589         DestroyWindow(hwnd);
5590     }
5591
5592     DestroyWindow(parent);
5593
5594     hwnd = CreateWindowExA(0, "my_button_class", "test", BS_PUSHBUTTON | WS_POPUP | WS_VISIBLE,
5595                            0, 0, 50, 14, 0, 0, 0, NULL);
5596     ok(hwnd != 0, "Failed to create button window\n");
5597
5598     SetForegroundWindow(hwnd);
5599     flush_events();
5600
5601     SetActiveWindow(hwnd);
5602     SetFocus(0);
5603     flush_sequence();
5604
5605     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
5606     ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
5607
5608     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
5609     ok_sequence(WmLButtonUpSeq, "WM_LBUTTONUP on a button", FALSE);
5610
5611     flush_sequence();
5612     zfont = GetStockObject(SYSTEM_FONT);
5613     SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
5614     UpdateWindow(hwnd);
5615     ok_sequence(WmSetFontButtonSeq, "WM_SETFONT on a button", FALSE);
5616
5617     DestroyWindow(hwnd);
5618 }
5619
5620 /****************** static message test *************************/
5621 static const struct message WmSetFontStaticSeq[] =
5622 {
5623     { WM_SETFONT, sent },
5624     { WM_PAINT, sent|defwinproc|optional },
5625     { WM_ERASEBKGND, sent|defwinproc|optional },
5626     { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
5627     { 0 }
5628 };
5629
5630 static WNDPROC old_static_proc;
5631
5632 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5633 {
5634     static LONG defwndproc_counter = 0;
5635     LRESULT ret;
5636     struct recvd_message msg;
5637
5638     if (ignore_message( message )) return 0;
5639
5640     msg.hwnd = hwnd;
5641     msg.message = message;
5642     msg.flags = sent|wparam|lparam;
5643     if (defwndproc_counter) msg.flags |= defwinproc;
5644     msg.wParam = wParam;
5645     msg.lParam = lParam;
5646     msg.descr = "static";
5647     add_message(&msg);
5648
5649     defwndproc_counter++;
5650     ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
5651     defwndproc_counter--;
5652
5653     return ret;
5654 }
5655
5656 static void subclass_static(void)
5657 {
5658     WNDCLASSA cls;
5659
5660     if (!GetClassInfoA(0, "static", &cls)) assert(0);
5661
5662     old_static_proc = cls.lpfnWndProc;
5663
5664     cls.hInstance = GetModuleHandle(0);
5665     cls.lpfnWndProc = static_hook_proc;
5666     cls.lpszClassName = "my_static_class";
5667     UnregisterClass(cls.lpszClassName, cls.hInstance);
5668     if (!RegisterClassA(&cls)) assert(0);
5669 }
5670
5671 static void test_static_messages(void)
5672 {
5673     /* FIXME: make as comprehensive as the button message test */
5674     static const struct
5675     {
5676         DWORD style;
5677         DWORD dlg_code;
5678         const struct message *setfont;
5679     } static_ctrl[] = {
5680         { SS_LEFT, DLGC_STATIC,
5681           WmSetFontStaticSeq }
5682     };
5683     unsigned int i;
5684     HWND hwnd;
5685     DWORD dlg_code;
5686
5687     subclass_static();
5688
5689     for (i = 0; i < sizeof(static_ctrl)/sizeof(static_ctrl[0]); i++)
5690     {
5691         hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
5692                                0, 0, 50, 14, 0, 0, 0, NULL);
5693         ok(hwnd != 0, "Failed to create static window\n");
5694
5695         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
5696         ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
5697
5698         ShowWindow(hwnd, SW_SHOW);
5699         UpdateWindow(hwnd);
5700         SetFocus(0);
5701         flush_sequence();
5702
5703         trace("static style %08x\n", static_ctrl[i].style);
5704         SendMessage(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
5705         ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
5706
5707         DestroyWindow(hwnd);
5708     }
5709 }
5710
5711 /****************** ComboBox message test *************************/
5712 #define ID_COMBOBOX 0x000f
5713
5714 static const struct message WmKeyDownComboSeq[] =
5715 {
5716     { WM_KEYDOWN, sent|wparam|lparam, VK_DOWN, 0 },
5717     { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(1000, LBN_SELCHANGE) },
5718     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDOK) },
5719     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELCHANGE) },
5720     { WM_CTLCOLOREDIT, sent|parent },
5721     { WM_KEYUP, sent|wparam|lparam, VK_DOWN, 0 },
5722     { 0 }
5723 };
5724
5725 static const struct message WmSetPosComboSeq[] =
5726 {
5727     { WM_WINDOWPOSCHANGING, sent },
5728     { WM_NCCALCSIZE, sent|wparam, TRUE },
5729     { WM_CHILDACTIVATE, sent },
5730     { WM_WINDOWPOSCHANGED, sent },
5731     { WM_MOVE, sent|defwinproc },
5732     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
5733     { WM_WINDOWPOSCHANGING, sent|defwinproc },
5734     { WM_NCCALCSIZE, sent|defwinproc|wparam, TRUE },
5735     { WM_WINDOWPOSCHANGED, sent|defwinproc },
5736     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
5737     { 0 }
5738 };
5739
5740 static WNDPROC old_combobox_proc;
5741
5742 static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5743 {
5744     static LONG defwndproc_counter = 0;
5745     LRESULT ret;
5746     struct recvd_message msg;
5747
5748     /* do not log painting messages */
5749     if (message != WM_PAINT &&
5750         message != WM_NCPAINT &&
5751         message != WM_SYNCPAINT &&
5752         message != WM_ERASEBKGND &&
5753         message != WM_NCHITTEST &&
5754         message != WM_GETTEXT &&
5755         !ignore_message( message ))
5756     {
5757         msg.hwnd = hwnd;
5758         msg.message = message;
5759         msg.flags = sent|wparam|lparam;
5760         if (defwndproc_counter) msg.flags |= defwinproc;
5761         msg.wParam = wParam;
5762         msg.lParam = lParam;
5763         msg.descr = "combo";
5764         add_message(&msg);
5765     }
5766
5767     defwndproc_counter++;
5768     ret = CallWindowProcA(old_combobox_proc, hwnd, message, wParam, lParam);
5769     defwndproc_counter--;
5770
5771     return ret;
5772 }
5773
5774 static void subclass_combobox(void)
5775 {
5776     WNDCLASSA cls;
5777
5778     if (!GetClassInfoA(0, "ComboBox", &cls)) assert(0);
5779
5780     old_combobox_proc = cls.lpfnWndProc;
5781
5782     cls.hInstance = GetModuleHandle(0);
5783     cls.lpfnWndProc = combobox_hook_proc;
5784     cls.lpszClassName = "my_combobox_class";
5785     UnregisterClass(cls.lpszClassName, cls.hInstance);
5786     if (!RegisterClassA(&cls)) assert(0);
5787 }
5788
5789 static void test_combobox_messages(void)
5790 {
5791     HWND parent, combo;
5792     LRESULT ret;
5793
5794     subclass_combobox();
5795
5796     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5797                              100, 100, 200, 200, 0, 0, 0, NULL);
5798     ok(parent != 0, "Failed to create parent window\n");
5799     flush_sequence();
5800
5801     combo = CreateWindowEx(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
5802                            0, 0, 100, 150, parent, (HMENU)ID_COMBOBOX, 0, NULL);
5803     ok(combo != 0, "Failed to create combobox window\n");
5804
5805     UpdateWindow(combo);
5806
5807     ret = SendMessage(combo, WM_GETDLGCODE, 0, 0);
5808     ok(ret == (DLGC_WANTCHARS | DLGC_WANTARROWS), "wrong dlg_code %08lx\n", ret);
5809
5810     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
5811     ok(ret == 0, "expected 0, got %ld\n", ret);
5812     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 1");
5813     ok(ret == 1, "expected 1, got %ld\n", ret);
5814     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 2");
5815     ok(ret == 2, "expected 2, got %ld\n", ret);
5816
5817     SendMessage(combo, CB_SETCURSEL, 0, 0);
5818     SetFocus(combo);
5819     flush_sequence();
5820
5821     log_all_parent_messages++;
5822     SendMessage(combo, WM_KEYDOWN, VK_DOWN, 0);
5823     SendMessage(combo, WM_KEYUP, VK_DOWN, 0);
5824     log_all_parent_messages--;
5825     ok_sequence(WmKeyDownComboSeq, "WM_KEYDOWN/VK_DOWN on a ComboBox", FALSE);
5826
5827     flush_sequence();
5828     SetWindowPos(combo, 0, 10, 10, 120, 130, SWP_NOZORDER);
5829     ok_sequence(WmSetPosComboSeq, "repositioning messages on a ComboBox", FALSE);
5830
5831     DestroyWindow(combo);
5832     DestroyWindow(parent);
5833 }
5834
5835 /****************** WM_IME_KEYDOWN message test *******************/
5836
5837 static const struct message WmImeKeydownMsgSeq_0[] =
5838 {
5839     { WM_IME_KEYDOWN, wparam, VK_RETURN },
5840     { WM_CHAR, wparam, 'A' },
5841     { 0 }
5842 };
5843
5844 static const struct message WmImeKeydownMsgSeq_1[] =
5845 {
5846     { WM_KEYDOWN, optional|wparam, VK_RETURN },
5847     { WM_CHAR,    optional|wparam, VK_RETURN },
5848     { 0 }
5849 };
5850
5851 static LRESULT WINAPI wmime_keydown_procA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5852 {
5853     struct recvd_message msg;
5854
5855     msg.hwnd = hwnd;
5856     msg.message = message;
5857     msg.flags = wparam|lparam;
5858     msg.wParam = wParam;
5859     msg.lParam = lParam;
5860     msg.descr = "wmime_keydown";
5861     add_message(&msg);
5862
5863     return DefWindowProcA(hwnd, message, wParam, lParam);
5864 }
5865
5866 static void register_wmime_keydown_class(void)
5867 {
5868     WNDCLASSA cls;
5869
5870     ZeroMemory(&cls, sizeof(WNDCLASSA));
5871     cls.lpfnWndProc = wmime_keydown_procA;
5872     cls.hInstance = GetModuleHandleA(0);
5873     cls.lpszClassName = "wmime_keydown_class";
5874     if (!RegisterClassA(&cls)) assert(0);
5875 }
5876
5877 static void test_wmime_keydown_message(void)
5878 {
5879     HWND hwnd;
5880     MSG msg;
5881
5882     trace("Message sequences by WM_IME_KEYDOWN\n");
5883
5884     register_wmime_keydown_class();
5885     hwnd = CreateWindowExA(0, "wmime_keydown_class", NULL, WS_OVERLAPPEDWINDOW,
5886                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5887                            NULL, NULL, 0);
5888     flush_events();
5889     flush_sequence();
5890
5891     SendMessage(hwnd, WM_IME_KEYDOWN, VK_RETURN, 0x1c0001);
5892     SendMessage(hwnd, WM_CHAR, 'A', 1);
5893     ok_sequence(WmImeKeydownMsgSeq_0, "WM_IME_KEYDOWN 0", FALSE);
5894
5895     while ( PeekMessage(&msg, 0, 0, 0, PM_REMOVE) )
5896     {
5897         TranslateMessage(&msg);
5898         DispatchMessage(&msg);
5899     }
5900     ok_sequence(WmImeKeydownMsgSeq_1, "WM_IME_KEYDOWN 1", FALSE);
5901
5902     DestroyWindow(hwnd);
5903 }
5904
5905 /************* painting message test ********************/
5906
5907 void dump_region(HRGN hrgn)
5908 {
5909     DWORD i, size;
5910     RGNDATA *data = NULL;
5911     RECT *rect;
5912
5913     if (!hrgn)
5914     {
5915         printf( "null region\n" );
5916         return;
5917     }
5918     if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
5919     if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
5920     GetRegionData( hrgn, size, data );
5921     printf("%d rects:", data->rdh.nCount );
5922     for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
5923         printf( " (%d,%d)-(%d,%d)", rect->left, rect->top, rect->right, rect->bottom );
5924     printf("\n");
5925     HeapFree( GetProcessHeap(), 0, data );
5926 }
5927
5928 static void check_update_rgn( HWND hwnd, HRGN hrgn )
5929 {
5930     INT ret;
5931     RECT r1, r2;
5932     HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
5933     HRGN update = CreateRectRgn( 0, 0, 0, 0 );
5934
5935     ret = GetUpdateRgn( hwnd, update, FALSE );
5936     ok( ret != ERROR, "GetUpdateRgn failed\n" );
5937     if (ret == NULLREGION)
5938     {
5939         ok( !hrgn, "Update region shouldn't be empty\n" );
5940     }
5941     else
5942     {
5943         if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
5944         {
5945             ok( 0, "Regions are different\n" );
5946             if (winetest_debug > 0)
5947             {
5948                 printf( "Update region: " );
5949                 dump_region( update );
5950                 printf( "Wanted region: " );
5951                 dump_region( hrgn );
5952             }
5953         }
5954     }
5955     GetRgnBox( update, &r1 );
5956     GetUpdateRect( hwnd, &r2, FALSE );
5957     ok( r1.left == r2.left && r1.top == r2.top && r1.right == r2.right && r1.bottom == r2.bottom,
5958         "Rectangles are different: %d,%d-%d,%d / %d,%d-%d,%d\n",
5959         r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom );
5960
5961     DeleteObject( tmp );
5962     DeleteObject( update );
5963 }
5964
5965 static const struct message WmInvalidateRgn[] = {
5966     { WM_NCPAINT, sent },
5967     { WM_GETTEXT, sent|defwinproc|optional },
5968     { 0 }
5969 };
5970
5971 static const struct message WmGetUpdateRect[] = {
5972     { WM_NCPAINT, sent },
5973     { WM_GETTEXT, sent|defwinproc|optional },
5974     { WM_PAINT, sent },
5975     { 0 }
5976 };
5977
5978 static const struct message WmInvalidateFull[] = {
5979     { WM_NCPAINT, sent|wparam, 1 },
5980     { WM_GETTEXT, sent|defwinproc|optional },
5981     { 0 }
5982 };
5983
5984 static const struct message WmInvalidateErase[] = {
5985     { WM_NCPAINT, sent|wparam, 1 },
5986     { WM_GETTEXT, sent|defwinproc|optional },
5987     { WM_ERASEBKGND, sent },
5988     { 0 }
5989 };
5990
5991 static const struct message WmInvalidatePaint[] = {
5992     { WM_PAINT, sent },
5993     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
5994     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5995     { 0 }
5996 };
5997
5998 static const struct message WmInvalidateErasePaint[] = {
5999     { WM_PAINT, sent },
6000     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
6001     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6002     { WM_ERASEBKGND, sent|beginpaint|optional },
6003     { 0 }
6004 };
6005
6006 static const struct message WmInvalidateErasePaint2[] = {
6007     { WM_PAINT, sent },
6008     { WM_NCPAINT, sent|beginpaint },
6009     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6010     { WM_ERASEBKGND, sent|beginpaint|optional },
6011     { 0 }
6012 };
6013
6014 static const struct message WmErase[] = {
6015     { WM_ERASEBKGND, sent },
6016     { 0 }
6017 };
6018
6019 static const struct message WmPaint[] = {
6020     { WM_PAINT, sent },
6021     { 0 }
6022 };
6023
6024 static const struct message WmParentOnlyPaint[] = {
6025     { WM_PAINT, sent|parent },
6026     { 0 }
6027 };
6028
6029 static const struct message WmInvalidateParent[] = {
6030     { WM_NCPAINT, sent|parent },
6031     { WM_GETTEXT, sent|defwinproc|parent|optional },
6032     { WM_ERASEBKGND, sent|parent },
6033     { 0 }
6034 };
6035
6036 static const struct message WmInvalidateParentChild[] = {
6037     { WM_NCPAINT, sent|parent },
6038     { WM_GETTEXT, sent|defwinproc|parent|optional },
6039     { WM_ERASEBKGND, sent|parent },
6040     { WM_NCPAINT, sent },
6041     { WM_GETTEXT, sent|defwinproc|optional },
6042     { WM_ERASEBKGND, sent },
6043     { 0 }
6044 };
6045
6046 static const struct message WmInvalidateParentChild2[] = {
6047     { WM_ERASEBKGND, sent|parent },
6048     { WM_NCPAINT, sent },
6049     { WM_GETTEXT, sent|defwinproc|optional },
6050     { WM_ERASEBKGND, sent },
6051     { 0 }
6052 };
6053
6054 static const struct message WmParentPaint[] = {
6055     { WM_PAINT, sent|parent },
6056     { WM_PAINT, sent },
6057     { 0 }
6058 };
6059
6060 static const struct message WmParentPaintNc[] = {
6061     { WM_PAINT, sent|parent },
6062     { WM_PAINT, sent },
6063     { WM_NCPAINT, sent|beginpaint },
6064     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6065     { WM_ERASEBKGND, sent|beginpaint|optional },
6066     { 0 }
6067 };
6068
6069 static const struct message WmChildPaintNc[] = {
6070     { WM_PAINT, sent },
6071     { WM_NCPAINT, sent|beginpaint },
6072     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6073     { WM_ERASEBKGND, sent|beginpaint|optional },
6074     { 0 }
6075 };
6076
6077 static const struct message WmParentErasePaint[] = {
6078     { WM_PAINT, sent|parent },
6079     { WM_NCPAINT, sent|parent|beginpaint },
6080     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
6081     { WM_ERASEBKGND, sent|parent|beginpaint|optional },
6082     { WM_PAINT, sent },
6083     { WM_NCPAINT, sent|beginpaint },
6084     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6085     { WM_ERASEBKGND, sent|beginpaint|optional },
6086     { 0 }
6087 };
6088
6089 static const struct message WmParentOnlyNcPaint[] = {
6090     { WM_PAINT, sent|parent },
6091     { WM_NCPAINT, sent|parent|beginpaint },
6092     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
6093     { 0 }
6094 };
6095
6096 static const struct message WmSetParentStyle[] = {
6097     { WM_STYLECHANGING, sent|parent },
6098     { WM_STYLECHANGED, sent|parent },
6099     { 0 }
6100 };
6101
6102 static void test_paint_messages(void)
6103 {
6104     BOOL ret;
6105     RECT rect;
6106     POINT pt;
6107     MSG msg;
6108     HWND hparent, hchild;
6109     HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
6110     HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
6111     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
6112                                 100, 100, 200, 200, 0, 0, 0, NULL);
6113     ok (hwnd != 0, "Failed to create overlapped window\n");
6114
6115     ShowWindow( hwnd, SW_SHOW );
6116     UpdateWindow( hwnd );
6117     flush_events();
6118     flush_sequence();
6119
6120     check_update_rgn( hwnd, 0 );
6121     SetRectRgn( hrgn, 10, 10, 20, 20 );
6122     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
6123     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6124     check_update_rgn( hwnd, hrgn );
6125     SetRectRgn( hrgn2, 20, 20, 30, 30 );
6126     ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
6127     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6128     CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
6129     check_update_rgn( hwnd, hrgn );
6130     /* validate everything */
6131     ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
6132     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6133     check_update_rgn( hwnd, 0 );
6134
6135     /* test empty region */
6136     SetRectRgn( hrgn, 10, 10, 10, 15 );
6137     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
6138     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6139     check_update_rgn( hwnd, 0 );
6140     /* test empty rect */
6141     SetRect( &rect, 10, 10, 10, 15 );
6142     ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
6143     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6144     check_update_rgn( hwnd, 0 );
6145
6146     /* flush pending messages */
6147     flush_events();
6148     flush_sequence();
6149
6150     GetClientRect( hwnd, &rect );
6151     SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
6152     /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
6153      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
6154      */
6155     trace("testing InvalidateRect(0, NULL, FALSE)\n");
6156     SetRectEmpty( &rect );
6157     ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) should fail\n");
6158     check_update_rgn( hwnd, hrgn );
6159     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
6160     flush_events();
6161     ok_sequence( WmPaint, "Paint", FALSE );
6162     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
6163     check_update_rgn( hwnd, 0 );
6164
6165     /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
6166      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
6167      */
6168     trace("testing ValidateRect(0, NULL)\n");
6169     SetRectEmpty( &rect );
6170     if (ValidateRect(0, &rect))  /* not supported on Win9x */
6171     {
6172         check_update_rgn( hwnd, hrgn );
6173         ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
6174         flush_events();
6175         ok_sequence( WmPaint, "Paint", FALSE );
6176         RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
6177         check_update_rgn( hwnd, 0 );
6178     }
6179
6180     trace("testing InvalidateRgn(0, NULL, FALSE)\n");
6181     SetLastError(0xdeadbeef);
6182     ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
6183     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef,
6184        "wrong error code %d\n", GetLastError());
6185     check_update_rgn( hwnd, 0 );
6186     flush_events();
6187     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
6188
6189     trace("testing ValidateRgn(0, NULL)\n");
6190     SetLastError(0xdeadbeef);
6191     ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
6192     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
6193        broken( GetLastError() == 0xdeadbeef ) /* win9x */,
6194        "wrong error code %d\n", GetLastError());
6195     check_update_rgn( hwnd, 0 );
6196     flush_events();
6197     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
6198
6199     trace("testing UpdateWindow(NULL)\n");
6200     SetLastError(0xdeadbeef);
6201     ok(!UpdateWindow(NULL), "UpdateWindow(NULL) should fail\n");
6202     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
6203        broken( GetLastError() == 0xdeadbeef ) /* win9x */,
6204        "wrong error code %d\n", GetLastError());
6205     check_update_rgn( hwnd, 0 );
6206     flush_events();
6207     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
6208
6209     /* now with frame */
6210     SetRectRgn( hrgn, -5, -5, 20, 20 );
6211
6212     /* flush pending messages */
6213     flush_events();
6214     flush_sequence();
6215     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6216     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
6217
6218     SetRectRgn( hrgn, 0, 0, 20, 20 );  /* GetUpdateRgn clips to client area */
6219     check_update_rgn( hwnd, hrgn );
6220
6221     flush_sequence();
6222     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
6223     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
6224
6225     flush_sequence();
6226     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
6227     ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
6228
6229     GetClientRect( hwnd, &rect );
6230     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
6231     check_update_rgn( hwnd, hrgn );
6232
6233     flush_sequence();
6234     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
6235     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
6236
6237     flush_sequence();
6238     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
6239     ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
6240     check_update_rgn( hwnd, 0 );
6241
6242     flush_sequence();
6243     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
6244     ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
6245     check_update_rgn( hwnd, 0 );
6246
6247     flush_sequence();
6248     SetRectRgn( hrgn, 0, 0, 100, 100 );
6249     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
6250     SetRectRgn( hrgn, 0, 0, 50, 100 );
6251     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
6252     SetRectRgn( hrgn, 50, 0, 100, 100 );
6253     check_update_rgn( hwnd, hrgn );
6254     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
6255     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );  /* must not generate messages, everything is valid */
6256     check_update_rgn( hwnd, 0 );
6257
6258     flush_sequence();
6259     SetRectRgn( hrgn, 0, 0, 100, 100 );
6260     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
6261     SetRectRgn( hrgn, 0, 0, 100, 50 );
6262     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
6263     ok_sequence( WmErase, "Erase", FALSE );
6264     SetRectRgn( hrgn, 0, 50, 100, 100 );
6265     check_update_rgn( hwnd, hrgn );
6266
6267     flush_sequence();
6268     SetRectRgn( hrgn, 0, 0, 100, 100 );
6269     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
6270     SetRectRgn( hrgn, 0, 0, 50, 50 );
6271     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
6272     ok_sequence( WmPaint, "Paint", FALSE );
6273
6274     flush_sequence();
6275     SetRectRgn( hrgn, -4, -4, -2, -2 );
6276     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6277     SetRectRgn( hrgn, -200, -200, -198, -198 );
6278     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
6279     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
6280
6281     flush_sequence();
6282     SetRectRgn( hrgn, -4, -4, -2, -2 );
6283     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6284     SetRectRgn( hrgn, -4, -4, -3, -3 );
6285     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
6286     SetRectRgn( hrgn, 0, 0, 1, 1 );
6287     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
6288     ok_sequence( WmPaint, "Paint", FALSE );
6289
6290     flush_sequence();
6291     SetRectRgn( hrgn, -4, -4, -1, -1 );
6292     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6293     RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
6294     /* make sure no WM_PAINT was generated */
6295     flush_events();
6296     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
6297
6298     flush_sequence();
6299     SetRectRgn( hrgn, -4, -4, -1, -1 );
6300     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6301     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
6302     {
6303         if (msg.hwnd == hwnd && msg.message == WM_PAINT)
6304         {
6305             /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
6306             INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
6307             ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
6308             ret = GetUpdateRect( hwnd, &rect, FALSE );
6309             ok( ret, "Invalid GetUpdateRect result %d\n", ret );
6310             /* this will send WM_NCPAINT and validate the non client area */
6311             ret = GetUpdateRect( hwnd, &rect, TRUE );
6312             ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
6313         }
6314         DispatchMessage( &msg );
6315     }
6316     ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
6317
6318     DestroyWindow( hwnd );
6319
6320     /* now test with a child window */
6321
6322     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
6323                               100, 100, 200, 200, 0, 0, 0, NULL);
6324     ok (hparent != 0, "Failed to create parent window\n");
6325
6326     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
6327                            10, 10, 100, 100, hparent, 0, 0, NULL);
6328     ok (hchild != 0, "Failed to create child window\n");
6329
6330     ShowWindow( hparent, SW_SHOW );
6331     UpdateWindow( hparent );
6332     UpdateWindow( hchild );
6333     flush_events();
6334     flush_sequence();
6335     log_all_parent_messages++;
6336
6337     SetRect( &rect, 0, 0, 50, 50 );
6338     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6339     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
6340     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
6341
6342     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6343     pt.x = pt.y = 0;
6344     MapWindowPoints( hchild, hparent, &pt, 1 );
6345     SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
6346     check_update_rgn( hchild, hrgn );
6347     SetRectRgn( hrgn, 0, 0, 50, 50 );
6348     check_update_rgn( hparent, hrgn );
6349     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6350     ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
6351     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
6352     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
6353
6354     flush_events();
6355     ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
6356
6357     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6358     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6359     ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
6360     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
6361     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
6362
6363     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6364     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
6365     ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
6366
6367     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
6368     flush_sequence();
6369     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6370     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6371     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
6372
6373     /* flush all paint messages */
6374     flush_events();
6375     flush_sequence();
6376
6377     /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
6378     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6379     SetRectRgn( hrgn, 0, 0, 50, 50 );
6380     check_update_rgn( hparent, hrgn );
6381     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6382     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6383     SetRectRgn( hrgn, 0, 0, 50, 50 );
6384     check_update_rgn( hparent, hrgn );
6385
6386     /* flush all paint messages */
6387     flush_events();
6388     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
6389     flush_sequence();
6390
6391     /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
6392     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6393     SetRectRgn( hrgn, 0, 0, 50, 50 );
6394     check_update_rgn( hparent, hrgn );
6395     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6396     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6397     SetRectRgn( hrgn2, 10, 10, 50, 50 );
6398     CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
6399     check_update_rgn( hparent, hrgn );
6400     /* flush all paint messages */
6401     flush_events();
6402     flush_sequence();
6403
6404     /* same as above but parent gets completely validated */
6405     SetRect( &rect, 20, 20, 30, 30 );
6406     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6407     SetRectRgn( hrgn, 20, 20, 30, 30 );
6408     check_update_rgn( hparent, hrgn );
6409     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6410     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6411     check_update_rgn( hparent, 0 );  /* no update region */
6412     flush_events();
6413     ok_sequence( WmEmptySeq, "WmEmpty", FALSE );  /* and no paint messages */
6414
6415     /* make sure RDW_VALIDATE on child doesn't have the same effect */
6416     flush_sequence();
6417     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6418     SetRectRgn( hrgn, 20, 20, 30, 30 );
6419     check_update_rgn( hparent, hrgn );
6420     RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
6421     SetRectRgn( hrgn, 20, 20, 30, 30 );
6422     check_update_rgn( hparent, hrgn );
6423
6424     /* same as above but normal WM_PAINT doesn't validate parent */
6425     flush_sequence();
6426     SetRect( &rect, 20, 20, 30, 30 );
6427     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6428     SetRectRgn( hrgn, 20, 20, 30, 30 );
6429     check_update_rgn( hparent, hrgn );
6430     /* no WM_PAINT in child while parent still pending */
6431     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6432     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6433     while (PeekMessage( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6434     ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
6435
6436     flush_sequence();
6437     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6438     /* no WM_PAINT in child while parent still pending */
6439     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6440     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6441     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
6442     /* now that parent is valid child should get WM_PAINT */
6443     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6444     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6445     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6446     ok_sequence( WmEmptySeq, "No other message", FALSE );
6447
6448     /* same thing with WS_CLIPCHILDREN in parent */
6449     flush_sequence();
6450     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
6451     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
6452     /* changing style invalidates non client area, but we need to invalidate something else to see it */
6453     RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
6454     ok_sequence( WmEmptySeq, "No message", FALSE );
6455     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
6456     ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
6457
6458     flush_sequence();
6459     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
6460     SetRectRgn( hrgn, 20, 20, 30, 30 );
6461     check_update_rgn( hparent, hrgn );
6462     /* no WM_PAINT in child while parent still pending */
6463     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6464     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6465     /* WM_PAINT in parent first */
6466     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6467     ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
6468
6469     /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
6470     flush_sequence();
6471     SetRect( &rect, 0, 0, 30, 30 );
6472     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
6473     SetRectRgn( hrgn, 0, 0, 30, 30 );
6474     check_update_rgn( hparent, hrgn );
6475     flush_events();
6476     ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
6477
6478     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
6479     flush_sequence();
6480     SetRect( &rect, -10, 0, 30, 30 );
6481     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
6482     SetRect( &rect, 0, 0, 20, 20 );
6483     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
6484     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
6485     ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
6486
6487     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
6488     flush_sequence();
6489     SetRect( &rect, -10, 0, 30, 30 );
6490     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
6491     SetRect( &rect, 0, 0, 100, 100 );
6492     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
6493     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
6494     ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
6495     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6496     ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
6497
6498     /* test RDW_INTERNALPAINT behavior */
6499
6500     flush_sequence();
6501     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
6502     flush_events();
6503     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
6504
6505     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
6506     flush_events();
6507     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
6508
6509     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
6510     flush_events();
6511     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
6512
6513     assert( GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
6514     UpdateWindow( hparent );
6515     flush_events();
6516     flush_sequence();
6517     trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
6518     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6519     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
6520                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6521     flush_events();
6522     ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
6523
6524     UpdateWindow( hparent );
6525     flush_events();
6526     flush_sequence();
6527     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
6528     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6529     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
6530                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6531     flush_events();
6532     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
6533
6534     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
6535     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
6536     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
6537     flush_events();
6538     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
6539
6540     assert( !(GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
6541     UpdateWindow( hparent );
6542     flush_events();
6543     flush_sequence();
6544     trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
6545     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6546     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
6547                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6548     flush_events();
6549     ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
6550
6551     UpdateWindow( hparent );
6552     flush_events();
6553     flush_sequence();
6554     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
6555     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6556     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
6557                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6558     flush_events();
6559     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
6560
6561     ok(GetWindowLong( hparent, GWL_STYLE ) & WS_VISIBLE, "parent should be visible\n");
6562     ok(GetWindowLong( hchild, GWL_STYLE ) & WS_VISIBLE, "child should be visible\n");
6563
6564     UpdateWindow( hparent );
6565     flush_events();
6566     flush_sequence();
6567     trace("testing SetWindowPos(-10000, -10000) on child\n");
6568     SetWindowPos( hchild, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
6569     check_update_rgn( hchild, 0 );
6570     flush_events();
6571
6572 #if 0 /* this one doesn't pass under Wine yet */
6573     UpdateWindow( hparent );
6574     flush_events();
6575     flush_sequence();
6576     trace("testing ShowWindow(SW_MINIMIZE) on child\n");
6577     ShowWindow( hchild, SW_MINIMIZE );
6578     check_update_rgn( hchild, 0 );
6579     flush_events();
6580 #endif
6581
6582     UpdateWindow( hparent );
6583     flush_events();
6584     flush_sequence();
6585     trace("testing SetWindowPos(-10000, -10000) on parent\n");
6586     SetWindowPos( hparent, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
6587     check_update_rgn( hparent, 0 );
6588     flush_events();
6589
6590     log_all_parent_messages--;
6591     DestroyWindow( hparent );
6592     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
6593
6594     /* tests for moving windows off-screen (needs simple WS_POPUP windows) */
6595
6596     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_POPUP | WS_VISIBLE,
6597                               100, 100, 200, 200, 0, 0, 0, NULL);
6598     ok (hparent != 0, "Failed to create parent window\n");
6599
6600     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
6601                            10, 10, 100, 100, hparent, 0, 0, NULL);
6602     ok (hchild != 0, "Failed to create child window\n");
6603
6604     ShowWindow( hparent, SW_SHOW );
6605     UpdateWindow( hparent );
6606     UpdateWindow( hchild );
6607     flush_events();
6608     flush_sequence();
6609
6610     /* moving child outside of parent boundaries changes update region */
6611     SetRect( &rect, 0, 0, 40, 40 );
6612     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6613     SetRectRgn( hrgn, 0, 0, 40, 40 );
6614     check_update_rgn( hchild, hrgn );
6615     MoveWindow( hchild, -10, 10, 100, 100, FALSE );
6616     SetRectRgn( hrgn, 10, 0, 40, 40 );
6617     check_update_rgn( hchild, hrgn );
6618     MoveWindow( hchild, -10, -10, 100, 100, FALSE );
6619     SetRectRgn( hrgn, 10, 10, 40, 40 );
6620     check_update_rgn( hchild, hrgn );
6621
6622     /* moving parent off-screen does too */
6623     SetRect( &rect, 0, 0, 100, 100 );
6624     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
6625     SetRectRgn( hrgn, 0, 0, 100, 100 );
6626     check_update_rgn( hparent, hrgn );
6627     SetRectRgn( hrgn, 10, 10, 40, 40 );
6628     check_update_rgn( hchild, hrgn );
6629     MoveWindow( hparent, -20, -20, 200, 200, FALSE );
6630     SetRectRgn( hrgn, 20, 20, 100, 100 );
6631     check_update_rgn( hparent, hrgn );
6632     SetRectRgn( hrgn, 30, 30, 40, 40 );
6633     check_update_rgn( hchild, hrgn );
6634
6635     /* invalidated region is cropped by the parent rects */
6636     SetRect( &rect, 0, 0, 50, 50 );
6637     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6638     SetRectRgn( hrgn, 30, 30, 50, 50 );
6639     check_update_rgn( hchild, hrgn );
6640
6641     DestroyWindow( hparent );
6642     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
6643     flush_sequence();
6644
6645     DeleteObject( hrgn );
6646     DeleteObject( hrgn2 );
6647 }
6648
6649 struct wnd_event
6650 {
6651     HWND hwnd;
6652     HANDLE grand_child;
6653     HANDLE start_event;
6654     HANDLE stop_event;
6655 };
6656
6657 static DWORD WINAPI thread_proc(void *param)
6658 {
6659     MSG msg;
6660     struct wnd_event *wnd_event = param;
6661
6662     wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
6663                                       100, 100, 200, 200, 0, 0, 0, NULL);
6664     ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
6665
6666     SetEvent(wnd_event->start_event);
6667
6668     while (GetMessage(&msg, 0, 0, 0))
6669     {
6670         TranslateMessage(&msg);
6671         DispatchMessage(&msg);
6672     }
6673
6674     ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
6675
6676     return 0;
6677 }
6678
6679 static DWORD CALLBACK create_grand_child_thread( void *param )
6680 {
6681     struct wnd_event *wnd_event = param;
6682     HWND hchild;
6683     MSG msg;
6684
6685     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
6686                              WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
6687     ok (hchild != 0, "Failed to create child window\n");
6688     flush_events();
6689     flush_sequence();
6690     SetEvent( wnd_event->start_event );
6691
6692     for (;;)
6693     {
6694         MsgWaitForMultipleObjects(0, NULL, FALSE, 1000, QS_ALLINPUT);
6695         if (!IsWindow( hchild )) break;  /* will be destroyed when parent thread exits */
6696         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
6697     }
6698     return 0;
6699 }
6700
6701 static DWORD CALLBACK create_child_thread( void *param )
6702 {
6703     struct wnd_event *wnd_event = param;
6704     struct wnd_event child_event;
6705     DWORD ret, tid;
6706     MSG msg;
6707
6708     child_event.hwnd = CreateWindowExA(0, "TestWindowClass", "Test child",
6709                              WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
6710     ok (child_event.hwnd != 0, "Failed to create child window\n");
6711     SetFocus( child_event.hwnd );
6712     flush_events();
6713     flush_sequence();
6714     child_event.start_event = wnd_event->start_event;
6715     wnd_event->grand_child = CreateThread(NULL, 0, create_grand_child_thread, &child_event, 0, &tid);
6716     for (;;)
6717     {
6718         DWORD ret = MsgWaitForMultipleObjects(1, &child_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
6719         if (ret != 1) break;
6720         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
6721     }
6722     ret = WaitForSingleObject( wnd_event->stop_event, 5000 );
6723     ok( !ret, "WaitForSingleObject failed %x\n", ret );
6724     return 0;
6725 }
6726
6727 static void test_interthread_messages(void)
6728 {
6729     HANDLE hThread;
6730     DWORD tid;
6731     WNDPROC proc;
6732     MSG msg;
6733     char buf[256];
6734     int len, expected_len;
6735     struct wnd_event wnd_event;
6736     BOOL ret;
6737
6738     wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
6739     if (!wnd_event.start_event)
6740     {
6741         win_skip("skipping interthread message test under win9x\n");
6742         return;
6743     }
6744
6745     hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
6746     ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
6747
6748     ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6749
6750     CloseHandle(wnd_event.start_event);
6751
6752     SetLastError(0xdeadbeef);
6753     ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeeded\n");
6754     ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == 0xdeadbeef,
6755        "wrong error code %d\n", GetLastError());
6756
6757     proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
6758     ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %d\n", GetLastError());
6759
6760     expected_len = lstrlenA("window caption text");
6761     memset(buf, 0, sizeof(buf));
6762     SetLastError(0xdeadbeef);
6763     len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
6764     ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %d, len %d, expected len %d\n", GetLastError(), len, expected_len);
6765     ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
6766
6767     msg.hwnd = wnd_event.hwnd;
6768     msg.message = WM_GETTEXT;
6769     msg.wParam = sizeof(buf);
6770     msg.lParam = (LPARAM)buf;
6771     memset(buf, 0, sizeof(buf));
6772     SetLastError(0xdeadbeef);
6773     len = DispatchMessageA(&msg);
6774     ok((!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY) || broken(len), /* nt4 */
6775        "DispatchMessageA(WM_GETTEXT) succeeded on another thread window: ret %d, error %d\n", len, GetLastError());
6776
6777     /* the following test causes an exception in user.exe under win9x */
6778     msg.hwnd = wnd_event.hwnd;
6779     msg.message = WM_TIMER;
6780     msg.wParam = 0;
6781     msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
6782     SetLastError(0xdeadbeef);
6783     len = DispatchMessageA(&msg);
6784     ok(!len && GetLastError() == 0xdeadbeef,
6785        "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %d\n", len, GetLastError());
6786
6787     ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
6788     ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
6789
6790     ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6791     CloseHandle(hThread);
6792
6793     ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
6794
6795     wnd_event.hwnd = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6796                               100, 100, 200, 200, 0, 0, 0, NULL);
6797     ok (wnd_event.hwnd != 0, "Failed to create parent window\n");
6798     flush_events();
6799     flush_sequence();
6800     log_all_parent_messages++;
6801     wnd_event.start_event = CreateEventA( NULL, TRUE, FALSE, NULL );
6802     wnd_event.stop_event = CreateEventA( NULL, TRUE, FALSE, NULL );
6803     hThread = CreateThread( NULL, 0, create_child_thread, &wnd_event, 0, &tid );
6804     for (;;)
6805     {
6806         ret = MsgWaitForMultipleObjects(1, &wnd_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
6807         if (ret != 1) break;
6808         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
6809     }
6810     ok( !ret, "MsgWaitForMultipleObjects failed %x\n", ret );
6811     /* now wait for the thread without processing messages; this shouldn't deadlock */
6812     SetEvent( wnd_event.stop_event );
6813     ret = WaitForSingleObject( hThread, 5000 );
6814     ok( !ret, "WaitForSingleObject failed %x\n", ret );
6815     CloseHandle( hThread );
6816
6817     ret = WaitForSingleObject( wnd_event.grand_child, 5000 );
6818     ok( !ret, "WaitForSingleObject failed %x\n", ret );
6819     CloseHandle( wnd_event.grand_child );
6820
6821     CloseHandle( wnd_event.start_event );
6822     CloseHandle( wnd_event.stop_event );
6823     flush_events();
6824     ok_sequence(WmExitThreadSeq, "destroy child on thread exit", FALSE);
6825     log_all_parent_messages--;
6826     DestroyWindow( wnd_event.hwnd );
6827 }
6828
6829
6830 static const struct message WmVkN[] = {
6831     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6832     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6833     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6834     { WM_CHAR, wparam|lparam, 'n', 1 },
6835     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
6836     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6837     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6838     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6839     { 0 }
6840 };
6841 static const struct message WmShiftVkN[] = {
6842     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
6843     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
6844     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
6845     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6846     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6847     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6848     { WM_CHAR, wparam|lparam, 'N', 1 },
6849     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
6850     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6851     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6852     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6853     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
6854     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
6855     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
6856     { 0 }
6857 };
6858 static const struct message WmCtrlVkN[] = {
6859     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6860     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6861     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6862     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6863     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6864     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6865     { WM_CHAR, wparam|lparam, 0x000e, 1 },
6866     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
6867     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6868     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6869     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6870     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6871     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6872     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6873     { 0 }
6874 };
6875 static const struct message WmCtrlVkN_2[] = {
6876     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6877     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6878     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6879     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6880     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6881     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
6882     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6883     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6884     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6885     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6886     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6887     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6888     { 0 }
6889 };
6890 static const struct message WmAltVkN[] = {
6891     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6892     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6893     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6894     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6895     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
6896     { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
6897     { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
6898     { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
6899     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
6900     { HCBT_SYSCOMMAND, hook },
6901     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
6902     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6903     { 0x00AE, sent|defwinproc|optional }, /* XP */
6904     { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
6905     { WM_INITMENU, sent|defwinproc },
6906     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6907     { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
6908     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6909     { WM_CAPTURECHANGED, sent|defwinproc },
6910     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
6911     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6912     { WM_EXITMENULOOP, sent|defwinproc },
6913     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
6914     { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
6915     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6916     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
6917     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6918     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6919     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6920     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6921     { 0 }
6922 };
6923 static const struct message WmAltVkN_2[] = {
6924     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6925     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6926     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6927     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6928     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
6929     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
6930     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6931     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
6932     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6933     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6934     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6935     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6936     { 0 }
6937 };
6938 static const struct message WmCtrlAltVkN[] = {
6939     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6940     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6941     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6942     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6943     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6944     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6945     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6946     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
6947     { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
6948     { WM_CHAR, optional },
6949     { WM_CHAR, sent|optional },
6950     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6951     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
6952     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6953     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6954     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6955     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6956     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6957     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6958     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6959     { 0 }
6960 };
6961 static const struct message WmCtrlShiftVkN[] = {
6962     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6963     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6964     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6965     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
6966     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
6967     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
6968     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6969     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6970     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
6971     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6972     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6973     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6974     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
6975     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
6976     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
6977     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6978     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6979     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6980     { 0 }
6981 };
6982 static const struct message WmCtrlAltShiftVkN[] = {
6983     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6984     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6985     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6986     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6987     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6988     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6989     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
6990     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
6991     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
6992     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6993     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
6994     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
6995     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6996     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
6997     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6998     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
6999     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
7000     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
7001     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
7002     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
7003     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
7004     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
7005     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
7006     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
7007     { 0 }
7008 };
7009 static const struct message WmAltPressRelease[] = {
7010     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
7011     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
7012     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
7013     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
7014     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
7015     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
7016     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
7017     { HCBT_SYSCOMMAND, hook },
7018     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
7019     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
7020     { WM_INITMENU, sent|defwinproc },
7021     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7022     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
7023     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7024
7025     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
7026
7027     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7028     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
7029     { WM_CAPTURECHANGED, sent|defwinproc },
7030     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
7031     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7032     { WM_EXITMENULOOP, sent|defwinproc },
7033     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
7034     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
7035     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
7036     { 0 }
7037 };
7038 static const struct message WmShiftMouseButton[] = {
7039     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
7040     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
7041     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
7042     { WM_MOUSEMOVE, wparam|optional, 0, 0 },
7043     { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
7044     { WM_LBUTTONDOWN, wparam, MK_LBUTTON|MK_SHIFT, 0 },
7045     { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON|MK_SHIFT, 0 },
7046     { WM_LBUTTONUP, wparam, MK_SHIFT, 0 },
7047     { WM_LBUTTONUP, sent|wparam, MK_SHIFT, 0 },
7048     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
7049     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
7050     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
7051     { 0 }
7052 };
7053 static const struct message WmF1Seq[] = {
7054     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
7055     { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
7056     { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
7057     { WM_KEYF1, wparam|lparam, 0, 0 },
7058     { WM_KEYF1, sent|wparam|lparam, 0, 0 },
7059     { WM_HELP, sent|defwinproc },
7060     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
7061     { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
7062     { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
7063     { 0 }
7064 };
7065 static const struct message WmVkAppsSeq[] = {
7066     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
7067     { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
7068     { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
7069     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
7070     { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
7071     { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
7072     { WM_CONTEXTMENU, lparam, /*hwnd*/0, -1 },
7073     { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, -1 },
7074     { 0 }
7075 };
7076 static const struct message WmVkF10Seq[] = {
7077     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
7078     { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
7079     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
7080     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
7081     { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
7082     { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
7083     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
7084     { HCBT_SYSCOMMAND, hook },
7085     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
7086     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
7087     { WM_INITMENU, sent|defwinproc },
7088     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7089     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
7090     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7091
7092     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0x10000001 }, /* XP */
7093
7094     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
7095     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7096     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
7097     { WM_CAPTURECHANGED, sent|defwinproc },
7098     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
7099     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7100     { WM_EXITMENULOOP, sent|defwinproc },
7101     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
7102     { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
7103     { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
7104     { 0 }
7105 };
7106 static const struct message WmShiftF10Seq[] = {
7107     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
7108     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
7109     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x00000001 },
7110     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
7111     { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
7112     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
7113     { WM_CONTEXTMENU, sent|defwinproc|lparam, /*hwnd*/0, -1 },
7114     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
7115     { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
7116     { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
7117     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
7118     { HCBT_SYSCOMMAND, hook },
7119     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
7120     { WM_INITMENU, sent|defwinproc },
7121     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
7122     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xd0000001 }, /* XP */
7123     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0x10000001 }, /* XP */
7124     { WM_CAPTURECHANGED, sent|defwinproc|wparam|lparam, 0, 0 },
7125     { WM_MENUSELECT, sent|defwinproc|wparam|lparam, 0xffff0000, 0 },
7126     { WM_EXITMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
7127     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 }, /* XP */
7128     { WM_KEYUP, wparam|lparam, VK_ESCAPE, 0xc0000001 },
7129     { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
7130     { 0 }
7131 };
7132
7133 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
7134 {
7135     MSG msg;
7136
7137     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
7138     {
7139         struct recvd_message log_msg;
7140
7141         /* ignore some unwanted messages */
7142         if (msg.message == WM_MOUSEMOVE ||
7143             msg.message == WM_TIMER ||
7144             ignore_message( msg.message ))
7145             continue;
7146
7147         log_msg.hwnd = msg.hwnd;
7148         log_msg.message = msg.message;
7149         log_msg.flags = wparam|lparam;
7150         log_msg.wParam = msg.wParam;
7151         log_msg.lParam = msg.lParam;
7152         log_msg.descr = "accel";
7153         add_message(&log_msg);
7154
7155         if (!hAccel || !TranslateAccelerator(hwnd, hAccel, &msg))
7156         {
7157             TranslateMessage(&msg);
7158             DispatchMessage(&msg);
7159         }
7160     }
7161 }
7162
7163 static void test_accelerators(void)
7164 {
7165     RECT rc;
7166     POINT pt;
7167     SHORT state;
7168     HACCEL hAccel;
7169     HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7170                                 100, 100, 200, 200, 0, 0, 0, NULL);
7171     BOOL ret;
7172
7173     assert(hwnd != 0);
7174     UpdateWindow(hwnd);
7175     flush_events();
7176     flush_sequence();
7177
7178     SetFocus(hwnd);
7179     ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
7180
7181     state = GetKeyState(VK_SHIFT);
7182     ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
7183     state = GetKeyState(VK_CAPITAL);
7184     ok(state == 0, "wrong CapsLock state %04x\n", state);
7185
7186     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(1));
7187     assert(hAccel != 0);
7188
7189     flush_events();
7190     pump_msg_loop(hwnd, 0);
7191     flush_sequence();
7192
7193     trace("testing VK_N press/release\n");
7194     flush_sequence();
7195     keybd_event('N', 0, 0, 0);
7196     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7197     pump_msg_loop(hwnd, hAccel);
7198     if (!sequence_cnt)  /* we didn't get any message */
7199     {
7200         skip( "queuing key events not supported\n" );
7201         goto done;
7202     }
7203     ok_sequence(WmVkN, "VK_N press/release", FALSE);
7204
7205     trace("testing Shift+VK_N press/release\n");
7206     flush_sequence();
7207     keybd_event(VK_SHIFT, 0, 0, 0);
7208     keybd_event('N', 0, 0, 0);
7209     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7210     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7211     pump_msg_loop(hwnd, hAccel);
7212     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
7213
7214     trace("testing Ctrl+VK_N press/release\n");
7215     flush_sequence();
7216     keybd_event(VK_CONTROL, 0, 0, 0);
7217     keybd_event('N', 0, 0, 0);
7218     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7219     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7220     pump_msg_loop(hwnd, hAccel);
7221     ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
7222
7223     trace("testing Alt+VK_N press/release\n");
7224     flush_sequence();
7225     keybd_event(VK_MENU, 0, 0, 0);
7226     keybd_event('N', 0, 0, 0);
7227     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7228     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7229     pump_msg_loop(hwnd, hAccel);
7230     ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
7231
7232     trace("testing Ctrl+Alt+VK_N press/release 1\n");
7233     flush_sequence();
7234     keybd_event(VK_CONTROL, 0, 0, 0);
7235     keybd_event(VK_MENU, 0, 0, 0);
7236     keybd_event('N', 0, 0, 0);
7237     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7238     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7239     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7240     pump_msg_loop(hwnd, hAccel);
7241     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
7242
7243     ret = DestroyAcceleratorTable(hAccel);
7244     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
7245
7246     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(2));
7247     assert(hAccel != 0);
7248
7249     trace("testing VK_N press/release\n");
7250     flush_sequence();
7251     keybd_event('N', 0, 0, 0);
7252     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7253     pump_msg_loop(hwnd, hAccel);
7254     ok_sequence(WmVkN, "VK_N press/release", FALSE);
7255
7256     trace("testing Shift+VK_N press/release\n");
7257     flush_sequence();
7258     keybd_event(VK_SHIFT, 0, 0, 0);
7259     keybd_event('N', 0, 0, 0);
7260     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7261     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7262     pump_msg_loop(hwnd, hAccel);
7263     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
7264
7265     trace("testing Ctrl+VK_N press/release 2\n");
7266     flush_sequence();
7267     keybd_event(VK_CONTROL, 0, 0, 0);
7268     keybd_event('N', 0, 0, 0);
7269     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7270     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7271     pump_msg_loop(hwnd, hAccel);
7272     ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
7273
7274     trace("testing Alt+VK_N press/release 2\n");
7275     flush_sequence();
7276     keybd_event(VK_MENU, 0, 0, 0);
7277     keybd_event('N', 0, 0, 0);
7278     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7279     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7280     pump_msg_loop(hwnd, hAccel);
7281     ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
7282
7283     trace("testing Ctrl+Alt+VK_N press/release 2\n");
7284     flush_sequence();
7285     keybd_event(VK_CONTROL, 0, 0, 0);
7286     keybd_event(VK_MENU, 0, 0, 0);
7287     keybd_event('N', 0, 0, 0);
7288     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7289     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7290     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7291     pump_msg_loop(hwnd, hAccel);
7292     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
7293
7294     trace("testing Ctrl+Shift+VK_N press/release\n");
7295     flush_sequence();
7296     keybd_event(VK_CONTROL, 0, 0, 0);
7297     keybd_event(VK_SHIFT, 0, 0, 0);
7298     keybd_event('N', 0, 0, 0);
7299     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7300     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7301     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7302     pump_msg_loop(hwnd, hAccel);
7303     ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
7304
7305     trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
7306     flush_sequence();
7307     keybd_event(VK_CONTROL, 0, 0, 0);
7308     keybd_event(VK_MENU, 0, 0, 0);
7309     keybd_event(VK_SHIFT, 0, 0, 0);
7310     keybd_event('N', 0, 0, 0);
7311     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7312     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7313     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7314     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7315     pump_msg_loop(hwnd, hAccel);
7316     ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
7317
7318     ret = DestroyAcceleratorTable(hAccel);
7319     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
7320     hAccel = 0;
7321
7322     trace("testing Alt press/release\n");
7323     flush_sequence();
7324     keybd_event(VK_MENU, 0, 0, 0);
7325     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7326     keybd_event(VK_MENU, 0, 0, 0);
7327     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7328     pump_msg_loop(hwnd, 0);
7329     /* this test doesn't pass in Wine for managed windows */
7330     ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
7331
7332     trace("testing VK_F1 press/release\n");
7333     keybd_event(VK_F1, 0, 0, 0);
7334     keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
7335     pump_msg_loop(hwnd, 0);
7336     ok_sequence(WmF1Seq, "F1 press/release", FALSE);
7337
7338     trace("testing VK_APPS press/release\n");
7339     keybd_event(VK_APPS, 0, 0, 0);
7340     keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
7341     pump_msg_loop(hwnd, 0);
7342     ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
7343
7344     trace("testing VK_F10 press/release\n");
7345     keybd_event(VK_F10, 0, 0, 0);
7346     keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
7347     keybd_event(VK_F10, 0, 0, 0);
7348     keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
7349     pump_msg_loop(hwnd, 0);
7350     ok_sequence(WmVkF10Seq, "VK_F10 press/release", TRUE);
7351
7352     trace("testing SHIFT+F10 press/release\n");
7353     keybd_event(VK_SHIFT, 0, 0, 0);
7354     keybd_event(VK_F10, 0, 0, 0);
7355     keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
7356     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7357     keybd_event(VK_ESCAPE, 0, 0, 0);
7358     keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
7359     pump_msg_loop(hwnd, 0);
7360     ok_sequence(WmShiftF10Seq, "SHIFT+F10 press/release", TRUE);
7361
7362     trace("testing Shift+MouseButton press/release\n");
7363     /* first, move mouse pointer inside of the window client area */
7364     GetClientRect(hwnd, &rc);
7365     MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
7366     rc.left += (rc.right - rc.left)/2;
7367     rc.top += (rc.bottom - rc.top)/2;
7368     SetCursorPos(rc.left, rc.top);
7369     SetActiveWindow(hwnd);
7370
7371     flush_events();
7372     flush_sequence();
7373     GetCursorPos(&pt);
7374     if (pt.x == rc.left && pt.y == rc.top)
7375     {
7376         int i;
7377         keybd_event(VK_SHIFT, 0, 0, 0);
7378         mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
7379         mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
7380         keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7381         pump_msg_loop(hwnd, 0);
7382         for (i = 0; i < sequence_cnt; i++) if (sequence[i].message == WM_LBUTTONDOWN) break;
7383         if (i < sequence_cnt)
7384             ok_sequence(WmShiftMouseButton, "Shift+MouseButton press/release", FALSE);
7385         else
7386             skip( "Shift+MouseButton event didn't get to the window\n" );
7387     }
7388
7389 done:
7390     if (hAccel) DestroyAcceleratorTable(hAccel);
7391     DestroyWindow(hwnd);
7392 }
7393
7394 /************* window procedures ********************/
7395
7396 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message, 
7397                              WPARAM wParam, LPARAM lParam)
7398 {
7399     static LONG defwndproc_counter = 0;
7400     static LONG beginpaint_counter = 0;
7401     LRESULT ret;
7402     struct recvd_message msg;
7403
7404     if (ignore_message( message )) return 0;
7405
7406     switch (message)
7407     {
7408         case WM_ENABLE:
7409         {
7410             LONG style = GetWindowLongA(hwnd, GWL_STYLE);
7411             ok((BOOL)wParam == !(style & WS_DISABLED),
7412                 "wrong WS_DISABLED state: %ld != %d\n", wParam, !(style & WS_DISABLED));
7413             break;
7414         }
7415
7416         case WM_CAPTURECHANGED:
7417             if (test_DestroyWindow_flag)
7418             {
7419                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
7420                 if (style & WS_CHILD)
7421                     lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
7422                 else if (style & WS_POPUP)
7423                     lParam = WND_POPUP_ID;
7424                 else
7425                     lParam = WND_PARENT_ID;
7426             }
7427             break;
7428
7429         case WM_NCDESTROY:
7430         {
7431             HWND capture;
7432
7433             ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
7434             capture = GetCapture();
7435             if (capture)
7436             {
7437                 ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
7438                 trace("current capture %p, releasing...\n", capture);
7439                 ReleaseCapture();
7440             }
7441         }
7442         /* fall through */
7443         case WM_DESTROY:
7444             if (pGetAncestor)
7445                 ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
7446             if (test_DestroyWindow_flag)
7447             {
7448                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
7449                 if (style & WS_CHILD)
7450                     lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
7451                 else if (style & WS_POPUP)
7452                     lParam = WND_POPUP_ID;
7453                 else
7454                     lParam = WND_PARENT_ID;
7455             }
7456             break;
7457
7458         /* test_accelerators() depends on this */
7459         case WM_NCHITTEST:
7460             return HTCLIENT;
7461
7462         /* ignore */
7463         case WM_MOUSEMOVE:
7464         case WM_MOUSEACTIVATE:
7465         case WM_NCMOUSEMOVE:
7466         case WM_SETCURSOR:
7467         case WM_IME_SELECT:
7468             return 0;
7469     }
7470
7471     msg.hwnd = hwnd;
7472     msg.message = message;
7473     msg.flags = sent|wparam|lparam;
7474     if (defwndproc_counter) msg.flags |= defwinproc;
7475     if (beginpaint_counter) msg.flags |= beginpaint;
7476     msg.wParam = wParam;
7477     msg.lParam = lParam;
7478     msg.descr = "MsgCheckProc";
7479     add_message(&msg);
7480
7481     if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
7482     {
7483         HWND parent = GetParent(hwnd);
7484         RECT rc;
7485         MINMAXINFO *minmax = (MINMAXINFO *)lParam;
7486
7487         GetClientRect(parent, &rc);
7488         trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
7489         trace("Reserved=%d,%d MaxSize=%d,%d MaxPos=%d,%d MinTrack=%d,%d MaxTrack=%d,%d\n",
7490               minmax->ptReserved.x, minmax->ptReserved.y,
7491               minmax->ptMaxSize.x, minmax->ptMaxSize.y,
7492               minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
7493               minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
7494               minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
7495
7496         ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n",
7497            minmax->ptMaxSize.x, rc.right);
7498         ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %d != %d\n",
7499            minmax->ptMaxSize.y, rc.bottom);
7500     }
7501
7502     if (message == WM_PAINT)
7503     {
7504         PAINTSTRUCT ps;
7505         beginpaint_counter++;
7506         BeginPaint( hwnd, &ps );
7507         beginpaint_counter--;
7508         EndPaint( hwnd, &ps );
7509         return 0;
7510     }
7511
7512     defwndproc_counter++;
7513     ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam) 
7514                   : DefWindowProcA(hwnd, message, wParam, lParam);
7515     defwndproc_counter--;
7516
7517     return ret;
7518 }
7519
7520 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7521 {
7522     return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
7523 }
7524
7525 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7526 {
7527     return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
7528 }
7529
7530 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7531 {
7532     static LONG defwndproc_counter = 0;
7533     LRESULT ret;
7534     struct recvd_message msg;
7535
7536     if (ignore_message( message )) return 0;
7537
7538     switch (message)
7539     {
7540     case WM_QUERYENDSESSION:
7541     case WM_ENDSESSION:
7542         lParam &= ~0x01;  /* Vista adds a 0x01 flag */
7543         break;
7544     }
7545
7546     msg.hwnd = hwnd;
7547     msg.message = message;
7548     msg.flags = sent|wparam|lparam;
7549     if (defwndproc_counter) msg.flags |= defwinproc;
7550     msg.wParam = wParam;
7551     msg.lParam = lParam;
7552     msg.descr = "popup";
7553     add_message(&msg);
7554
7555     if (message == WM_CREATE)
7556     {
7557         DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
7558         SetWindowLongA(hwnd, GWL_STYLE, style);
7559     }
7560
7561     defwndproc_counter++;
7562     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7563     defwndproc_counter--;
7564
7565     return ret;
7566 }
7567
7568 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7569 {
7570     static LONG defwndproc_counter = 0;
7571     static LONG beginpaint_counter = 0;
7572     LRESULT ret;
7573     struct recvd_message msg;
7574
7575     if (ignore_message( message )) return 0;
7576
7577     if (log_all_parent_messages ||
7578         message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
7579         message == WM_SETFOCUS || message == WM_KILLFOCUS ||
7580         message == WM_ENABLE || message == WM_ENTERIDLE ||
7581         message == WM_DRAWITEM || message == WM_COMMAND ||
7582         message == WM_IME_SETCONTEXT)
7583     {
7584         switch (message)
7585         {
7586             /* ignore */
7587             case WM_NCHITTEST:
7588                 return HTCLIENT;
7589             case WM_SETCURSOR:
7590             case WM_MOUSEMOVE:
7591             case WM_NCMOUSEMOVE:
7592                 return 0;
7593
7594             case WM_ERASEBKGND:
7595             {
7596                 RECT rc;
7597                 INT ret = GetClipBox((HDC)wParam, &rc);
7598
7599                 trace("WM_ERASEBKGND: GetClipBox()=%d, (%d,%d-%d,%d)\n",
7600                        ret, rc.left, rc.top, rc.right, rc.bottom);
7601                 break;
7602             }
7603         }
7604
7605         msg.hwnd = hwnd;
7606         msg.message = message;
7607         msg.flags = sent|parent|wparam|lparam;
7608         if (defwndproc_counter) msg.flags |= defwinproc;
7609         if (beginpaint_counter) msg.flags |= beginpaint;
7610         msg.wParam = wParam;
7611         msg.lParam = lParam;
7612         msg.descr = "parent";
7613         add_message(&msg);
7614     }
7615
7616     if (message == WM_PAINT)
7617     {
7618         PAINTSTRUCT ps;
7619         beginpaint_counter++;
7620         BeginPaint( hwnd, &ps );
7621         beginpaint_counter--;
7622         EndPaint( hwnd, &ps );
7623         return 0;
7624     }
7625
7626     defwndproc_counter++;
7627     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7628     defwndproc_counter--;
7629
7630     return ret;
7631 }
7632
7633 static INT_PTR CALLBACK StopQuitMsgCheckProcA(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
7634 {
7635     if (message == WM_CREATE)
7636         PostMessage(hwnd, WM_CLOSE, 0, 0);
7637     else if (message == WM_CLOSE)
7638     {
7639         /* Only the first WM_QUIT will survive the window destruction */
7640         PostMessage(hwnd, WM_USER, 0x1234, 0x5678);
7641         PostMessage(hwnd, WM_QUIT, 0x1234, 0x5678);
7642         PostMessage(hwnd, WM_QUIT, 0x4321, 0x8765);
7643     }
7644
7645     return DefWindowProcA(hwnd, message, wp, lp);
7646 }
7647
7648 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7649 {
7650     static LONG defwndproc_counter = 0;
7651     LRESULT ret;
7652     struct recvd_message msg;
7653
7654     if (ignore_message( message )) return 0;
7655
7656     if (test_def_id)
7657     {
7658         DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
7659         ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
7660         if (after_end_dialog)
7661             ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
7662         else
7663             ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
7664     }
7665
7666     msg.hwnd = hwnd;
7667     msg.message = message;
7668     msg.flags = sent|wparam|lparam;
7669     if (defwndproc_counter) msg.flags |= defwinproc;
7670     msg.wParam = wParam;
7671     msg.lParam = lParam;
7672     msg.descr = "dialog";
7673     add_message(&msg);
7674
7675     defwndproc_counter++;
7676     ret = DefDlgProcA(hwnd, message, wParam, lParam);
7677     defwndproc_counter--;
7678
7679     return ret;
7680 }
7681
7682 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7683 {
7684     static LONG defwndproc_counter = 0;
7685     LRESULT ret;
7686     struct recvd_message msg;
7687
7688     /* log only specific messages we are interested in */
7689     switch (message)
7690     {
7691 #if 0 /* probably log these as well */
7692     case WM_ACTIVATE:
7693     case WM_SETFOCUS:
7694     case WM_KILLFOCUS:
7695 #endif
7696     case WM_SHOWWINDOW:
7697     case WM_SIZE:
7698     case WM_MOVE:
7699     case WM_GETMINMAXINFO:
7700     case WM_WINDOWPOSCHANGING:
7701     case WM_WINDOWPOSCHANGED:
7702         break;
7703
7704     default: /* ignore */
7705         /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
7706         return DefWindowProcA(hwnd, message, wParam, lParam);
7707     }
7708
7709     msg.hwnd = hwnd;
7710     msg.message = message;
7711     msg.flags = sent|wparam|lparam;
7712     if (defwndproc_counter) msg.flags |= defwinproc;
7713     msg.wParam = wParam;
7714     msg.lParam = lParam;
7715     msg.descr = "show";
7716     add_message(&msg);
7717
7718     defwndproc_counter++;
7719     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7720     defwndproc_counter--;
7721
7722     return ret;
7723 }
7724
7725 static LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
7726 {
7727     switch (msg)
7728     {
7729         case WM_CREATE: return 0;
7730         case WM_PAINT:
7731         {
7732             MSG msg2;
7733             static int i = 0;
7734
7735             if (i < 256)
7736             {
7737                 i++;
7738                 if (PeekMessageA(&msg2, 0, 0, 0, 1))
7739                 {
7740                     TranslateMessage(&msg2);
7741                     DispatchMessage(&msg2);
7742                 }
7743                 i--;
7744             }
7745             else ok(broken(1), "infinite loop\n");
7746             if ( i == 0)
7747                 paint_loop_done = 1;
7748             return DefWindowProcA(hWnd,msg,wParam,lParam);
7749         }
7750     }
7751     return DefWindowProcA(hWnd,msg,wParam,lParam);
7752 }
7753
7754 static LRESULT WINAPI HotkeyMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7755 {
7756     static LONG defwndproc_counter = 0;
7757     LRESULT ret;
7758     struct recvd_message msg;
7759     DWORD queue_status;
7760
7761     if (ignore_message( message )) return 0;
7762
7763     if ((message >= WM_KEYFIRST && message <= WM_KEYLAST) ||
7764         message == WM_HOTKEY || message >= WM_APP)
7765     {
7766         msg.hwnd = hwnd;
7767         msg.message = message;
7768         msg.flags = sent|wparam|lparam;
7769         if (defwndproc_counter) msg.flags |= defwinproc;
7770         msg.wParam = wParam;
7771         msg.lParam = lParam;
7772         msg.descr = "HotkeyMsgCheckProcA";
7773         add_message(&msg);
7774     }
7775
7776     defwndproc_counter++;
7777     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7778     defwndproc_counter--;
7779
7780     if (message == WM_APP)
7781     {
7782         queue_status = GetQueueStatus(QS_HOTKEY);
7783         ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
7784         queue_status = GetQueueStatus(QS_POSTMESSAGE);
7785         ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
7786         PostMessageA(hwnd, WM_APP+1, 0, 0);
7787     }
7788     else if (message == WM_APP+1)
7789     {
7790         queue_status = GetQueueStatus(QS_HOTKEY);
7791         ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
7792     }
7793
7794     return ret;
7795 }
7796
7797 static BOOL RegisterWindowClasses(void)
7798 {
7799     WNDCLASSA cls;
7800     WNDCLASSW clsW;
7801
7802     cls.style = 0;
7803     cls.lpfnWndProc = MsgCheckProcA;
7804     cls.cbClsExtra = 0;
7805     cls.cbWndExtra = 0;
7806     cls.hInstance = GetModuleHandleA(0);
7807     cls.hIcon = 0;
7808     cls.hCursor = LoadCursorA(0, IDC_ARROW);
7809     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
7810     cls.lpszMenuName = NULL;
7811     cls.lpszClassName = "TestWindowClass";
7812     if(!RegisterClassA(&cls)) return FALSE;
7813
7814     cls.lpfnWndProc = HotkeyMsgCheckProcA;
7815     cls.lpszClassName = "HotkeyWindowClass";
7816     if(!RegisterClassA(&cls)) return FALSE;
7817
7818     cls.lpfnWndProc = ShowWindowProcA;
7819     cls.lpszClassName = "ShowWindowClass";
7820     if(!RegisterClassA(&cls)) return FALSE;
7821
7822     cls.lpfnWndProc = PopupMsgCheckProcA;
7823     cls.lpszClassName = "TestPopupClass";
7824     if(!RegisterClassA(&cls)) return FALSE;
7825
7826     cls.lpfnWndProc = ParentMsgCheckProcA;
7827     cls.lpszClassName = "TestParentClass";
7828     if(!RegisterClassA(&cls)) return FALSE;
7829
7830     cls.lpfnWndProc = StopQuitMsgCheckProcA;
7831     cls.lpszClassName = "StopQuitClass";
7832     if(!RegisterClassA(&cls)) return FALSE;
7833
7834     cls.lpfnWndProc = DefWindowProcA;
7835     cls.lpszClassName = "SimpleWindowClass";
7836     if(!RegisterClassA(&cls)) return FALSE;
7837
7838     cls.lpfnWndProc = PaintLoopProcA;
7839     cls.lpszClassName = "PaintLoopWindowClass";
7840     if(!RegisterClassA(&cls)) return FALSE;
7841
7842     cls.style = CS_NOCLOSE;
7843     cls.lpszClassName = "NoCloseWindowClass";
7844     if(!RegisterClassA(&cls)) return FALSE;
7845
7846     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
7847     cls.style = 0;
7848     cls.hInstance = GetModuleHandleA(0);
7849     cls.hbrBackground = 0;
7850     cls.lpfnWndProc = TestDlgProcA;
7851     cls.lpszClassName = "TestDialogClass";
7852     if(!RegisterClassA(&cls)) return FALSE;
7853
7854     clsW.style = 0;
7855     clsW.lpfnWndProc = MsgCheckProcW;
7856     clsW.cbClsExtra = 0;
7857     clsW.cbWndExtra = 0;
7858     clsW.hInstance = GetModuleHandleW(0);
7859     clsW.hIcon = 0;
7860     clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
7861     clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
7862     clsW.lpszMenuName = NULL;
7863     clsW.lpszClassName = testWindowClassW;
7864     RegisterClassW(&clsW);  /* ignore error, this fails on Win9x */
7865
7866     return TRUE;
7867 }
7868
7869 static BOOL is_our_logged_class(HWND hwnd)
7870 {
7871     char buf[256];
7872
7873     if (GetClassNameA(hwnd, buf, sizeof(buf)))
7874     {
7875         if (!lstrcmpiA(buf, "TestWindowClass") ||
7876             !lstrcmpiA(buf, "ShowWindowClass") ||
7877             !lstrcmpiA(buf, "TestParentClass") ||
7878             !lstrcmpiA(buf, "TestPopupClass") ||
7879             !lstrcmpiA(buf, "SimpleWindowClass") ||
7880             !lstrcmpiA(buf, "TestDialogClass") ||
7881             !lstrcmpiA(buf, "MDI_frame_class") ||
7882             !lstrcmpiA(buf, "MDI_client_class") ||
7883             !lstrcmpiA(buf, "MDI_child_class") ||
7884             !lstrcmpiA(buf, "my_button_class") ||
7885             !lstrcmpiA(buf, "my_edit_class") ||
7886             !lstrcmpiA(buf, "static") ||
7887             !lstrcmpiA(buf, "ListBox") ||
7888             !lstrcmpiA(buf, "ComboBox") ||
7889             !lstrcmpiA(buf, "MyDialogClass") ||
7890             !lstrcmpiA(buf, "#32770") ||
7891             !lstrcmpiA(buf, "#32768"))
7892         return TRUE;
7893     }
7894     return FALSE;
7895 }
7896
7897 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
7898
7899     HWND hwnd;
7900
7901     ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
7902
7903     if (nCode == HCBT_CLICKSKIPPED)
7904     {
7905         /* ignore this event, XP sends it a lot when switching focus between windows */
7906         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7907     }
7908
7909     if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
7910     {
7911         struct recvd_message msg;
7912
7913         msg.hwnd = 0;
7914         msg.message = nCode;
7915         msg.flags = hook|wparam|lparam;
7916         msg.wParam = wParam;
7917         msg.lParam = lParam;
7918         msg.descr = "CBT";
7919         add_message(&msg);
7920
7921         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7922     }
7923
7924     if (nCode == HCBT_DESTROYWND)
7925     {
7926         if (test_DestroyWindow_flag)
7927         {
7928             DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
7929             if (style & WS_CHILD)
7930                 lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
7931             else if (style & WS_POPUP)
7932                 lParam = WND_POPUP_ID;
7933             else
7934                 lParam = WND_PARENT_ID;
7935         }
7936     }
7937
7938     /* Log also SetFocus(0) calls */
7939     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
7940
7941     if (is_our_logged_class(hwnd))
7942     {
7943         struct recvd_message msg;
7944
7945         msg.hwnd = hwnd;
7946         msg.message = nCode;
7947         msg.flags = hook|wparam|lparam;
7948         msg.wParam = wParam;
7949         msg.lParam = lParam;
7950         msg.descr = "CBT";
7951         add_message(&msg);
7952     }
7953     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7954 }
7955
7956 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
7957                                     DWORD event,
7958                                     HWND hwnd,
7959                                     LONG object_id,
7960                                     LONG child_id,
7961                                     DWORD thread_id,
7962                                     DWORD event_time)
7963 {
7964     ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
7965
7966     /* ignore mouse cursor events */
7967     if (object_id == OBJID_CURSOR) return;
7968
7969     if (!hwnd || is_our_logged_class(hwnd))
7970     {
7971         struct recvd_message msg;
7972
7973         msg.hwnd = hwnd;
7974         msg.message = event;
7975         msg.flags = winevent_hook|wparam|lparam;
7976         msg.wParam = object_id;
7977         msg.lParam = child_id;
7978         msg.descr = "WEH";
7979         add_message(&msg);
7980     }
7981 }
7982
7983 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
7984 static const WCHAR wszAnsi[] = {'U',0};
7985
7986 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
7987 {
7988     switch (uMsg)
7989     {
7990     case CB_FINDSTRINGEXACT:
7991         trace("String: %p\n", (LPCWSTR)lParam);
7992         if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
7993             return 1;
7994         if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
7995             return 0;
7996         return -1;
7997     }
7998     return DefWindowProcW(hwnd, uMsg, wParam, lParam);
7999 }
8000
8001 static const struct message WmGetTextLengthAfromW[] = {
8002     { WM_GETTEXTLENGTH, sent },
8003     { WM_GETTEXT, sent|optional },
8004     { 0 }
8005 };
8006
8007 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
8008
8009 /* dummy window proc for WM_GETTEXTLENGTH test */
8010 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
8011 {
8012     switch(msg)
8013     {
8014     case WM_GETTEXTLENGTH:
8015         return lstrlenW(dummy_window_text) + 37;  /* some random length */
8016     case WM_GETTEXT:
8017         lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
8018         return lstrlenW( (LPWSTR)lp );
8019     default:
8020         return DefWindowProcW( hwnd, msg, wp, lp );
8021     }
8022 }
8023
8024 static void test_message_conversion(void)
8025 {
8026     static const WCHAR wszMsgConversionClass[] =
8027         {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
8028     WNDCLASSW cls;
8029     LRESULT lRes;
8030     HWND hwnd;
8031     WNDPROC wndproc, newproc;
8032     BOOL ret;
8033
8034     cls.style = 0;
8035     cls.lpfnWndProc = MsgConversionProcW;
8036     cls.cbClsExtra = 0;
8037     cls.cbWndExtra = 0;
8038     cls.hInstance = GetModuleHandleW(NULL);
8039     cls.hIcon = NULL;
8040     cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
8041     cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
8042     cls.lpszMenuName = NULL;
8043     cls.lpszClassName = wszMsgConversionClass;
8044     /* this call will fail on Win9x, but that doesn't matter as this test is
8045      * meaningless on those platforms */
8046     if(!RegisterClassW(&cls)) return;
8047
8048     hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
8049                            100, 100, 200, 200, 0, 0, 0, NULL);
8050     ok(hwnd != NULL, "Window creation failed\n");
8051
8052     /* {W, A} -> A */
8053
8054     wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
8055     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8056     ok(lRes == 0, "String should have been converted\n");
8057     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8058     ok(lRes == 1, "String shouldn't have been converted\n");
8059
8060     /* {W, A} -> W */
8061
8062     wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
8063     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8064     ok(lRes == 1, "String shouldn't have been converted\n");
8065     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8066     ok(lRes == 1, "String shouldn't have been converted\n");
8067
8068     /* Synchronous messages */
8069
8070     lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8071     ok(lRes == 0, "String should have been converted\n");
8072     lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8073     ok(lRes == 1, "String shouldn't have been converted\n");
8074
8075     /* Asynchronous messages */
8076
8077     SetLastError(0);
8078     lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8079     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8080         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8081     SetLastError(0);
8082     lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8083     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8084         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8085     SetLastError(0);
8086     lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8087     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8088         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8089     SetLastError(0);
8090     lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8091     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8092         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8093     SetLastError(0);
8094     lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8095     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8096         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8097     SetLastError(0);
8098     lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8099     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8100         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8101     SetLastError(0);
8102     lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
8103     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8104         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8105     SetLastError(0);
8106     lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
8107     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8108         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8109
8110     /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
8111
8112     hwnd = CreateWindowW (testWindowClassW, wszUnicode,
8113                           WS_OVERLAPPEDWINDOW,
8114                           100, 100, 200, 200, 0, 0, 0, NULL);
8115     assert(hwnd);
8116     flush_sequence();
8117     lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
8118     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
8119     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
8120         "got bad length %ld\n", lRes );
8121
8122     flush_sequence();
8123     lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
8124                             hwnd, WM_GETTEXTLENGTH, 0, 0);
8125     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
8126     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
8127         "got bad length %ld\n", lRes );
8128
8129     wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
8130     newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
8131     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
8132     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
8133                                      NULL, 0, NULL, NULL ) ||
8134         broken(lRes == lstrlenW(dummy_window_text) + 37),
8135         "got bad length %ld\n", lRes );
8136
8137     SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc );  /* restore old wnd proc */
8138     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
8139     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
8140                                      NULL, 0, NULL, NULL ) ||
8141         broken(lRes == lstrlenW(dummy_window_text) + 37),
8142         "got bad length %ld\n", lRes );
8143
8144     ret = DestroyWindow(hwnd);
8145     ok( ret, "DestroyWindow() error %d\n", GetLastError());
8146 }
8147
8148 struct timer_info
8149 {
8150     HWND hWnd;
8151     HANDLE handles[2];
8152     DWORD id;
8153 };
8154
8155 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
8156 {
8157 }
8158
8159 #define TIMER_ID  0x19
8160
8161 static DWORD WINAPI timer_thread_proc(LPVOID x)
8162 {
8163     struct timer_info *info = x;
8164     DWORD r;
8165
8166     r = KillTimer(info->hWnd, 0x19);
8167     ok(r,"KillTimer failed in thread\n");
8168     r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
8169     ok(r,"SetTimer failed in thread\n");
8170     ok(r==TIMER_ID,"SetTimer id different\n");
8171     r = SetEvent(info->handles[0]);
8172     ok(r,"SetEvent failed in thread\n");
8173     return 0;
8174 }
8175
8176 static void test_timers(void)
8177 {
8178     struct timer_info info;
8179     DWORD id;
8180
8181     info.hWnd = CreateWindow ("TestWindowClass", NULL,
8182        WS_OVERLAPPEDWINDOW ,
8183        CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
8184        NULL, NULL, 0);
8185
8186     info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
8187     ok(info.id, "SetTimer failed\n");
8188     ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
8189     info.handles[0] = CreateEvent(NULL,0,0,NULL);
8190     info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
8191
8192     WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
8193
8194     WaitForSingleObject(info.handles[1], INFINITE);
8195
8196     CloseHandle(info.handles[0]);
8197     CloseHandle(info.handles[1]);
8198
8199     ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
8200
8201     ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
8202 }
8203
8204 static int count = 0;
8205 static VOID CALLBACK callback_count(
8206     HWND hwnd,
8207     UINT uMsg,
8208     UINT_PTR idEvent,
8209     DWORD dwTime
8210 )
8211 {
8212     count++;
8213 }
8214
8215 static void test_timers_no_wnd(void)
8216 {
8217     UINT_PTR id, id2;
8218     MSG msg;
8219
8220     count = 0;
8221     id = SetTimer(NULL, 0, 100, callback_count);
8222     ok(id != 0, "did not get id from SetTimer.\n");
8223     id2 = SetTimer(NULL, id, 200, callback_count);
8224     ok(id2 == id, "did not get same id from SetTimer when replacing (%li expected %li).\n", id2, id);
8225     Sleep(150);
8226     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
8227     ok(count == 0, "did not get zero count as expected (%i).\n", count);
8228     Sleep(150);
8229     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
8230     ok(count == 1, "did not get one count as expected (%i).\n", count);
8231     KillTimer(NULL, id);
8232     Sleep(250);
8233     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
8234     ok(count == 1, "killing replaced timer did not work (%i).\n", count);
8235 }
8236
8237 /* Various win events with arbitrary parameters */
8238 static const struct message WmWinEventsSeq[] = {
8239     { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
8240     { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
8241     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
8242     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
8243     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
8244     { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
8245     { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
8246     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
8247     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
8248     /* our win event hook ignores OBJID_CURSOR events */
8249     /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
8250     { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
8251     { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
8252     { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
8253     { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
8254     { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
8255     { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
8256     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
8257     { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
8258     { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
8259     { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
8260     { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
8261     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
8262     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
8263     { 0 }
8264 };
8265 static const struct message WmWinEventCaretSeq[] = {
8266     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
8267     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
8268     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
8269     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
8270     { 0 }
8271 };
8272 static const struct message WmWinEventCaretSeq_2[] = {
8273     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
8274     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
8275     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
8276     { 0 }
8277 };
8278 static const struct message WmWinEventAlertSeq[] = {
8279     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
8280     { 0 }
8281 };
8282 static const struct message WmWinEventAlertSeq_2[] = {
8283     /* create window in the thread proc */
8284     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
8285     /* our test event */
8286     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
8287     { 0 }
8288 };
8289 static const struct message WmGlobalHookSeq_1[] = {
8290     /* create window in the thread proc */
8291     { HCBT_CREATEWND, hook|lparam, 0, 2 },
8292     /* our test events */
8293     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
8294     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
8295     { 0 }
8296 };
8297 static const struct message WmGlobalHookSeq_2[] = {
8298     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
8299     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
8300     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
8301     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
8302     { 0 }
8303 };
8304
8305 static const struct message WmMouseLLHookSeq[] = {
8306     { WM_MOUSEMOVE, hook },
8307     { WM_LBUTTONUP, hook },
8308     { WM_MOUSEMOVE, hook },
8309     { 0 }
8310 };
8311
8312 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
8313                                          DWORD event,
8314                                          HWND hwnd,
8315                                          LONG object_id,
8316                                          LONG child_id,
8317                                          DWORD thread_id,
8318                                          DWORD event_time)
8319 {
8320     char buf[256];
8321
8322     if (GetClassNameA(hwnd, buf, sizeof(buf)))
8323     {
8324         if (!lstrcmpiA(buf, "TestWindowClass") ||
8325             !lstrcmpiA(buf, "static"))
8326         {
8327             struct recvd_message msg;
8328
8329             msg.hwnd = hwnd;
8330             msg.message = event;
8331             msg.flags = winevent_hook|wparam|lparam;
8332             msg.wParam = object_id;
8333             msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
8334             msg.descr = "WEH_2";
8335             add_message(&msg);
8336         }
8337     }
8338 }
8339
8340 static HHOOK hCBT_global_hook;
8341 static DWORD cbt_global_hook_thread_id;
8342
8343 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
8344
8345     HWND hwnd;
8346     char buf[256];
8347
8348     if (nCode == HCBT_SYSCOMMAND)
8349     {
8350         struct recvd_message msg;
8351
8352         msg.hwnd = 0;
8353         msg.message = nCode;
8354         msg.flags = hook|wparam|lparam;
8355         msg.wParam = wParam;
8356         msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
8357         msg.descr = "CBT_2";
8358         add_message(&msg);
8359
8360         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
8361     }
8362     /* WH_MOUSE_LL hook */
8363     if (nCode == HC_ACTION)
8364     {
8365         MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
8366
8367         /* we can't test for real mouse events */
8368         if (mhll->flags & LLMHF_INJECTED)
8369         {
8370             struct recvd_message msg;
8371
8372             memset (&msg, 0, sizeof (msg));
8373             msg.message = wParam;
8374             msg.flags = hook;
8375             msg.descr = "CBT_2";
8376             add_message(&msg);
8377         }
8378         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
8379     }
8380
8381     /* Log also SetFocus(0) calls */
8382     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
8383
8384     if (GetClassNameA(hwnd, buf, sizeof(buf)))
8385     {
8386         if (!lstrcmpiA(buf, "TestWindowClass") ||
8387             !lstrcmpiA(buf, "static"))
8388         {
8389             struct recvd_message msg;
8390
8391             msg.hwnd = hwnd;
8392             msg.message = nCode;
8393             msg.flags = hook|wparam|lparam;
8394             msg.wParam = wParam;
8395             msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
8396             msg.descr = "CBT_2";
8397             add_message(&msg);
8398         }
8399     }
8400     return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
8401 }
8402
8403 static DWORD WINAPI win_event_global_thread_proc(void *param)
8404 {
8405     HWND hwnd;
8406     MSG msg;
8407     HANDLE hevent = *(HANDLE *)param;
8408
8409     assert(pNotifyWinEvent);
8410
8411     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
8412     assert(hwnd);
8413     trace("created thread window %p\n", hwnd);
8414
8415     *(HWND *)param = hwnd;
8416
8417     flush_sequence();
8418     /* this event should be received only by our new hook proc,
8419      * an old one does not expect an event from another thread.
8420      */
8421     pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
8422     SetEvent(hevent);
8423
8424     while (GetMessage(&msg, 0, 0, 0))
8425     {
8426         TranslateMessage(&msg);
8427         DispatchMessage(&msg);
8428     }
8429     return 0;
8430 }
8431
8432 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
8433 {
8434     HWND hwnd;
8435     MSG msg;
8436     HANDLE hevent = *(HANDLE *)param;
8437
8438     flush_sequence();
8439     /* these events should be received only by our new hook proc,
8440      * an old one does not expect an event from another thread.
8441      */
8442
8443     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
8444     assert(hwnd);
8445     trace("created thread window %p\n", hwnd);
8446
8447     *(HWND *)param = hwnd;
8448
8449     /* Windows doesn't like when a thread plays games with the focus,
8450        that leads to all kinds of misbehaviours and failures to activate
8451        a window. So, better keep next lines commented out.
8452     SetFocus(0);
8453     SetFocus(hwnd);*/
8454
8455     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
8456     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
8457
8458     SetEvent(hevent);
8459
8460     while (GetMessage(&msg, 0, 0, 0))
8461     {
8462         TranslateMessage(&msg);
8463         DispatchMessage(&msg);
8464     }
8465     return 0;
8466 }
8467
8468 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
8469 {
8470     HWND hwnd;
8471     MSG msg;
8472     HANDLE hevent = *(HANDLE *)param;
8473
8474     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
8475     assert(hwnd);
8476     trace("created thread window %p\n", hwnd);
8477
8478     *(HWND *)param = hwnd;
8479
8480     flush_sequence();
8481
8482     /* Windows doesn't like when a thread plays games with the focus,
8483      * that leads to all kinds of misbehaviours and failures to activate
8484      * a window. So, better don't generate a mouse click message below.
8485      */
8486     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8487     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
8488     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8489
8490     SetEvent(hevent);
8491     while (GetMessage(&msg, 0, 0, 0))
8492     {
8493         TranslateMessage(&msg);
8494         DispatchMessage(&msg);
8495     }
8496     return 0;
8497 }
8498
8499 static void test_winevents(void)
8500 {
8501     BOOL ret;
8502     MSG msg;
8503     HWND hwnd, hwnd2;
8504     UINT i;
8505     HANDLE hthread, hevent;
8506     DWORD tid;
8507     HWINEVENTHOOK hhook;
8508     const struct message *events = WmWinEventsSeq;
8509
8510     hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
8511                            WS_OVERLAPPEDWINDOW,
8512                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
8513                            NULL, NULL, 0);
8514     assert(hwnd);
8515
8516     /****** start of global hook test *************/
8517     hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
8518     if (!hCBT_global_hook)
8519     {
8520         ok(DestroyWindow(hwnd), "failed to destroy window\n");
8521         skip( "cannot set global hook\n" );
8522         return;
8523     }
8524
8525     hevent = CreateEventA(NULL, 0, 0, NULL);
8526     assert(hevent);
8527     hwnd2 = hevent;
8528
8529     hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
8530     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8531
8532     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8533
8534     ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
8535
8536     flush_sequence();
8537     /* this one should be received only by old hook proc */
8538     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
8539     /* this one should be received only by old hook proc */
8540     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
8541
8542     ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
8543
8544     ret = UnhookWindowsHookEx(hCBT_global_hook);
8545     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
8546
8547     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8548     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8549     CloseHandle(hthread);
8550     CloseHandle(hevent);
8551     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8552     /****** end of global hook test *************/
8553
8554     if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
8555     {
8556         ok(DestroyWindow(hwnd), "failed to destroy window\n");
8557         return;
8558     }
8559
8560     flush_sequence();
8561
8562     if (0)
8563     {
8564     /* this test doesn't pass under Win9x */
8565     /* win2k ignores events with hwnd == 0 */
8566     SetLastError(0xdeadbeef);
8567     pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
8568     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
8569        GetLastError() == 0xdeadbeef, /* Win9x */
8570        "unexpected error %d\n", GetLastError());
8571     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
8572     }
8573
8574     for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++)
8575         pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
8576
8577     ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
8578
8579     /****** start of event filtering test *************/
8580     hhook = pSetWinEventHook(
8581         EVENT_OBJECT_SHOW, /* 0x8002 */
8582         EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
8583         GetModuleHandleA(0), win_event_global_hook_proc,
8584         GetCurrentProcessId(), 0,
8585         WINEVENT_INCONTEXT);
8586     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
8587
8588     hevent = CreateEventA(NULL, 0, 0, NULL);
8589     assert(hevent);
8590     hwnd2 = hevent;
8591
8592     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
8593     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8594
8595     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8596
8597     ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
8598
8599     flush_sequence();
8600     /* this one should be received only by old hook proc */
8601     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
8602     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
8603     /* this one should be received only by old hook proc */
8604     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
8605
8606     ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
8607
8608     ret = pUnhookWinEvent(hhook);
8609     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8610
8611     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8612     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8613     CloseHandle(hthread);
8614     CloseHandle(hevent);
8615     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8616     /****** end of event filtering test *************/
8617
8618     /****** start of out of context event test *************/
8619     hhook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0,
8620         win_event_global_hook_proc, GetCurrentProcessId(), 0,
8621         WINEVENT_OUTOFCONTEXT);
8622     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
8623
8624     hevent = CreateEventA(NULL, 0, 0, NULL);
8625     assert(hevent);
8626     hwnd2 = hevent;
8627
8628     flush_sequence();
8629
8630     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
8631     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8632
8633     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8634
8635     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
8636     /* process pending winevent messages */
8637     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
8638     ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
8639
8640     flush_sequence();
8641     /* this one should be received only by old hook proc */
8642     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
8643     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
8644     /* this one should be received only by old hook proc */
8645     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
8646
8647     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
8648     /* process pending winevent messages */
8649     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
8650     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
8651
8652     ret = pUnhookWinEvent(hhook);
8653     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8654
8655     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8656     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8657     CloseHandle(hthread);
8658     CloseHandle(hevent);
8659     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8660     /****** end of out of context event test *************/
8661
8662     /****** start of MOUSE_LL hook test *************/
8663     hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
8664     /* WH_MOUSE_LL is not supported on Win9x platforms */
8665     if (!hCBT_global_hook)
8666     {
8667         win_skip("Skipping WH_MOUSE_LL test on this platform\n");
8668         goto skip_mouse_ll_hook_test;
8669     }
8670
8671     hevent = CreateEventA(NULL, 0, 0, NULL);
8672     assert(hevent);
8673     hwnd2 = hevent;
8674
8675     hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
8676     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8677
8678     while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
8679         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
8680
8681     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
8682     flush_sequence();
8683
8684     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8685     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
8686     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8687
8688     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
8689
8690     ret = UnhookWindowsHookEx(hCBT_global_hook);
8691     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
8692
8693     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8694     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8695     CloseHandle(hthread);
8696     CloseHandle(hevent);
8697     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8698     /****** end of MOUSE_LL hook test *************/
8699 skip_mouse_ll_hook_test:
8700
8701     ok(DestroyWindow(hwnd), "failed to destroy window\n");
8702 }
8703
8704 static void test_set_hook(void)
8705 {
8706     BOOL ret;
8707     HHOOK hhook;
8708     HWINEVENTHOOK hwinevent_hook;
8709
8710     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
8711     ok(hhook != 0, "local hook does not require hModule set to 0\n");
8712     UnhookWindowsHookEx(hhook);
8713
8714     if (0)
8715     {
8716     /* this test doesn't pass under Win9x: BUG! */
8717     SetLastError(0xdeadbeef);
8718     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
8719     ok(!hhook, "global hook requires hModule != 0\n");
8720     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
8721     }
8722
8723     SetLastError(0xdeadbeef);
8724     hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
8725     ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
8726     ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
8727        GetLastError() == 0xdeadbeef, /* Win9x */
8728        "unexpected error %d\n", GetLastError());
8729
8730     SetLastError(0xdeadbeef);
8731     ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
8732     ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
8733        GetLastError() == 0xdeadbeef, /* Win9x */
8734        "unexpected error %d\n", GetLastError());
8735
8736     if (!pSetWinEventHook || !pUnhookWinEvent) return;
8737
8738     /* even process local incontext hooks require hmodule */
8739     SetLastError(0xdeadbeef);
8740     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8741         GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
8742     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
8743     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
8744        GetLastError() == 0xdeadbeef, /* Win9x */
8745        "unexpected error %d\n", GetLastError());
8746
8747     /* even thread local incontext hooks require hmodule */
8748     SetLastError(0xdeadbeef);
8749     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8750         GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
8751     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
8752     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
8753        GetLastError() == 0xdeadbeef, /* Win9x */
8754        "unexpected error %d\n", GetLastError());
8755
8756     if (0)
8757     {
8758     /* these 3 tests don't pass under Win9x */
8759     SetLastError(0xdeadbeef);
8760     hwinevent_hook = pSetWinEventHook(1, 0, 0, win_event_proc,
8761         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8762     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
8763     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
8764
8765     SetLastError(0xdeadbeef);
8766     hwinevent_hook = pSetWinEventHook(-1, 1, 0, win_event_proc,
8767         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8768     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
8769     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
8770
8771     SetLastError(0xdeadbeef);
8772     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8773         0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
8774     ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
8775     ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
8776     }
8777
8778     SetLastError(0xdeadbeef);
8779     hwinevent_hook = pSetWinEventHook(0, 0, 0, win_event_proc,
8780         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8781     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
8782     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
8783     ret = pUnhookWinEvent(hwinevent_hook);
8784     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8785
8786 todo_wine {
8787     /* This call succeeds under win2k SP4, but fails under Wine.
8788        Does win2k test/use passed process id? */
8789     SetLastError(0xdeadbeef);
8790     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8791         0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
8792     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
8793     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
8794     ret = pUnhookWinEvent(hwinevent_hook);
8795     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8796 }
8797
8798     SetLastError(0xdeadbeef);
8799     ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
8800     ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
8801         GetLastError() == 0xdeadbeef, /* Win9x */
8802         "unexpected error %d\n", GetLastError());
8803 }
8804
8805 static const struct message ScrollWindowPaint1[] = {
8806     { WM_PAINT, sent },
8807     { WM_ERASEBKGND, sent|beginpaint },
8808     { WM_GETTEXTLENGTH, sent|optional },
8809     { WM_PAINT, sent|optional },
8810     { WM_NCPAINT, sent|beginpaint|optional },
8811     { WM_GETTEXT, sent|beginpaint|optional },
8812     { WM_GETTEXT, sent|beginpaint|optional },
8813     { WM_GETTEXT, sent|beginpaint|optional },
8814     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8815     { WM_ERASEBKGND, sent|beginpaint|optional },
8816     { 0 }
8817 };
8818
8819 static const struct message ScrollWindowPaint2[] = {
8820     { WM_PAINT, sent },
8821     { 0 }
8822 };
8823
8824 static void test_scrollwindowex(void)
8825 {
8826     HWND hwnd, hchild;
8827     RECT rect={0,0,130,130};
8828
8829     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
8830             WS_VISIBLE|WS_OVERLAPPEDWINDOW,
8831             100, 100, 200, 200, 0, 0, 0, NULL);
8832     ok (hwnd != 0, "Failed to create overlapped window\n");
8833     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", 
8834             WS_VISIBLE|WS_CAPTION|WS_CHILD,
8835             10, 10, 150, 150, hwnd, 0, 0, NULL);
8836     ok (hchild != 0, "Failed to create child\n");
8837     UpdateWindow(hwnd);
8838     flush_events();
8839     flush_sequence();
8840
8841     /* scroll without the child window */
8842     trace("start scroll\n");
8843     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
8844             SW_ERASE|SW_INVALIDATE);
8845     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
8846     trace("end scroll\n");
8847     flush_sequence();
8848     flush_events();
8849     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
8850     flush_events();
8851     flush_sequence();
8852
8853     /* Now without the SW_ERASE flag */
8854     trace("start scroll\n");
8855     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
8856     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
8857     trace("end scroll\n");
8858     flush_sequence();
8859     flush_events();
8860     ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", 0);
8861     flush_events();
8862     flush_sequence();
8863
8864     /* now scroll the child window as well */
8865     trace("start scroll\n");
8866     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
8867             SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
8868     /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
8869     /* windows sometimes a WM_MOVE */
8870     ok_sequence(WmEmptySeq, "ScrollWindowEx", TRUE);
8871     trace("end scroll\n");
8872     flush_sequence();
8873     flush_events();
8874     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
8875     flush_events();
8876     flush_sequence();
8877
8878     /* now scroll with ScrollWindow() */
8879     trace("start scroll with ScrollWindow\n");
8880     ScrollWindow( hwnd, 5, 5, NULL, NULL);
8881     trace("end scroll\n");
8882     flush_sequence();
8883     flush_events();
8884     ok_sequence(ScrollWindowPaint1, "ScrollWindow", 0);
8885
8886     ok(DestroyWindow(hchild), "failed to destroy window\n");
8887     ok(DestroyWindow(hwnd), "failed to destroy window\n");
8888     flush_sequence();
8889 }
8890
8891 static const struct message destroy_window_with_children[] = {
8892     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
8893     { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
8894     { 0x0090, sent|optional },
8895     { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
8896     { 0x0090, sent|optional },
8897     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
8898     { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8899     { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8900     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8901     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
8902     { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
8903     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
8904     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
8905     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
8906     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
8907     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
8908     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
8909     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
8910     { 0 }
8911 };
8912
8913 static void test_DestroyWindow(void)
8914 {
8915     BOOL ret;
8916     HWND parent, child1, child2, child3, child4, test;
8917     UINT_PTR child_id = WND_CHILD_ID + 1;
8918
8919     parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8920                              100, 100, 200, 200, 0, 0, 0, NULL);
8921     assert(parent != 0);
8922     child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8923                              0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
8924     assert(child1 != 0);
8925     child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8926                              0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
8927     assert(child2 != 0);
8928     child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8929                              0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
8930     assert(child3 != 0);
8931     child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
8932                              0, 0, 50, 50, parent, 0, 0, NULL);
8933     assert(child4 != 0);
8934
8935     /* test owner/parent of child2 */
8936     test = GetParent(child2);
8937     ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8938     ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
8939     if(pGetAncestor) {
8940         test = pGetAncestor(child2, GA_PARENT);
8941         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8942     }
8943     test = GetWindow(child2, GW_OWNER);
8944     ok(!test, "wrong owner %p\n", test);
8945
8946     test = SetParent(child2, parent);
8947     ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
8948
8949     /* test owner/parent of the parent */
8950     test = GetParent(parent);
8951     ok(!test, "wrong parent %p\n", test);
8952     ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
8953     if(pGetAncestor) {
8954         test = pGetAncestor(parent, GA_PARENT);
8955         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8956     }
8957     test = GetWindow(parent, GW_OWNER);
8958     ok(!test, "wrong owner %p\n", test);
8959
8960     /* test owner/parent of child1 */
8961     test = GetParent(child1);
8962     ok(test == parent, "wrong parent %p\n", test);
8963     ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
8964     if(pGetAncestor) {
8965         test = pGetAncestor(child1, GA_PARENT);
8966         ok(test == parent, "wrong parent %p\n", test);
8967     }
8968     test = GetWindow(child1, GW_OWNER);
8969     ok(!test, "wrong owner %p\n", test);
8970
8971     /* test owner/parent of child2 */
8972     test = GetParent(child2);
8973     ok(test == parent, "wrong parent %p\n", test);
8974     ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
8975     if(pGetAncestor) {
8976         test = pGetAncestor(child2, GA_PARENT);
8977         ok(test == parent, "wrong parent %p\n", test);
8978     }
8979     test = GetWindow(child2, GW_OWNER);
8980     ok(!test, "wrong owner %p\n", test);
8981
8982     /* test owner/parent of child3 */
8983     test = GetParent(child3);
8984     ok(test == child1, "wrong parent %p\n", test);
8985     ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
8986     if(pGetAncestor) {
8987         test = pGetAncestor(child3, GA_PARENT);
8988         ok(test == child1, "wrong parent %p\n", test);
8989     }
8990     test = GetWindow(child3, GW_OWNER);
8991     ok(!test, "wrong owner %p\n", test);
8992
8993     /* test owner/parent of child4 */
8994     test = GetParent(child4);
8995     ok(test == parent, "wrong parent %p\n", test);
8996     ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
8997     if(pGetAncestor) {
8998         test = pGetAncestor(child4, GA_PARENT);
8999         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
9000     }
9001     test = GetWindow(child4, GW_OWNER);
9002     ok(test == parent, "wrong owner %p\n", test);
9003
9004     flush_sequence();
9005
9006     trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
9007            parent, child1, child2, child3, child4);
9008
9009     SetCapture(child4);
9010     test = GetCapture();
9011     ok(test == child4, "wrong capture window %p\n", test);
9012
9013     test_DestroyWindow_flag = TRUE;
9014     ret = DestroyWindow(parent);
9015     ok( ret, "DestroyWindow() error %d\n", GetLastError());
9016     test_DestroyWindow_flag = FALSE;
9017     ok_sequence(destroy_window_with_children, "destroy window with children", 0);
9018
9019     ok(!IsWindow(parent), "parent still exists\n");
9020     ok(!IsWindow(child1), "child1 still exists\n");
9021     ok(!IsWindow(child2), "child2 still exists\n");
9022     ok(!IsWindow(child3), "child3 still exists\n");
9023     ok(!IsWindow(child4), "child4 still exists\n");
9024
9025     test = GetCapture();
9026     ok(!test, "wrong capture window %p\n", test);
9027 }
9028
9029
9030 static const struct message WmDispatchPaint[] = {
9031     { WM_NCPAINT, sent },
9032     { WM_GETTEXT, sent|defwinproc|optional },
9033     { WM_GETTEXT, sent|defwinproc|optional },
9034     { WM_ERASEBKGND, sent },
9035     { 0 }
9036 };
9037
9038 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9039 {
9040     if (message == WM_PAINT) return 0;
9041     return MsgCheckProcA( hwnd, message, wParam, lParam );
9042 }
9043
9044 static void test_DispatchMessage(void)
9045 {
9046     RECT rect;
9047     MSG msg;
9048     int count;
9049     HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
9050                                100, 100, 200, 200, 0, 0, 0, NULL);
9051     ShowWindow( hwnd, SW_SHOW );
9052     UpdateWindow( hwnd );
9053     flush_events();
9054     flush_sequence();
9055     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
9056
9057     SetRect( &rect, -5, -5, 5, 5 );
9058     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
9059     count = 0;
9060     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
9061     {
9062         if (msg.message != WM_PAINT) DispatchMessage( &msg );
9063         else
9064         {
9065             flush_sequence();
9066             DispatchMessage( &msg );
9067             /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
9068             if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
9069             else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
9070             if (++count > 10) break;
9071         }
9072     }
9073     ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
9074
9075     trace("now without DispatchMessage\n");
9076     flush_sequence();
9077     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
9078     count = 0;
9079     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
9080     {
9081         if (msg.message != WM_PAINT) DispatchMessage( &msg );
9082         else
9083         {
9084             HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
9085             flush_sequence();
9086             /* this will send WM_NCCPAINT just like DispatchMessage does */
9087             GetUpdateRgn( hwnd, hrgn, TRUE );
9088             ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
9089             DeleteObject( hrgn );
9090             GetClientRect( hwnd, &rect );
9091             ValidateRect( hwnd, &rect );  /* this will stop WM_PAINTs */
9092             ok( !count, "Got multiple WM_PAINTs\n" );
9093             if (++count > 10) break;
9094         }
9095     }
9096
9097     flush_sequence();
9098     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
9099     count = 0;
9100     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
9101     {
9102         if (msg.message != WM_PAINT) DispatchMessage( &msg );
9103         else
9104         {
9105             HDC hdc;
9106
9107             flush_sequence();
9108             hdc = BeginPaint( hwnd, NULL );
9109             ok( !hdc, "got valid hdc %p from BeginPaint\n", hdc );
9110             ok( !EndPaint( hwnd, NULL ), "EndPaint succeeded\n" );
9111             ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
9112             ok( !count, "Got multiple WM_PAINTs\n" );
9113             if (++count > 10) break;
9114         }
9115     }
9116     DestroyWindow(hwnd);
9117 }
9118
9119
9120 static const struct message WmUser[] = {
9121     { WM_USER, sent },
9122     { 0 }
9123 };
9124
9125 struct sendmsg_info
9126 {
9127     HWND  hwnd;
9128     DWORD timeout;
9129     DWORD ret;
9130 };
9131
9132 static DWORD CALLBACK send_msg_thread( LPVOID arg )
9133 {
9134     struct sendmsg_info *info = arg;
9135     SetLastError( 0xdeadbeef );
9136     info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
9137     if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT ||
9138                         broken(GetLastError() == 0),  /* win9x */
9139                         "unexpected error %d\n", GetLastError());
9140     return 0;
9141 }
9142
9143 static void wait_for_thread( HANDLE thread )
9144 {
9145     while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
9146     {
9147         MSG msg;
9148         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage(&msg);
9149     }
9150 }
9151
9152 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9153 {
9154     if (message == WM_USER) Sleep(200);
9155     return MsgCheckProcA( hwnd, message, wParam, lParam );
9156 }
9157
9158 static void test_SendMessageTimeout(void)
9159 {
9160     HANDLE thread;
9161     struct sendmsg_info info;
9162     DWORD tid;
9163     BOOL is_win9x;
9164
9165     info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
9166                                100, 100, 200, 200, 0, 0, 0, NULL);
9167     flush_events();
9168     flush_sequence();
9169
9170     info.timeout = 1000;
9171     info.ret = 0xdeadbeef;
9172     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9173     wait_for_thread( thread );
9174     CloseHandle( thread );
9175     ok( info.ret == 1, "SendMessageTimeout failed\n" );
9176     ok_sequence( WmUser, "WmUser", FALSE );
9177
9178     info.timeout = 1;
9179     info.ret = 0xdeadbeef;
9180     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9181     Sleep(100);  /* SendMessageTimeout should time out here */
9182     wait_for_thread( thread );
9183     CloseHandle( thread );
9184     ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
9185     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
9186
9187     /* 0 means infinite timeout (but not on win9x) */
9188     info.timeout = 0;
9189     info.ret = 0xdeadbeef;
9190     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9191     Sleep(100);
9192     wait_for_thread( thread );
9193     CloseHandle( thread );
9194     is_win9x = !info.ret;
9195     if (is_win9x) ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
9196     else ok_sequence( WmUser, "WmUser", FALSE );
9197
9198     /* timeout is treated as signed despite the prototype (but not on win9x) */
9199     info.timeout = 0x7fffffff;
9200     info.ret = 0xdeadbeef;
9201     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9202     Sleep(100);
9203     wait_for_thread( thread );
9204     CloseHandle( thread );
9205     ok( info.ret == 1, "SendMessageTimeout failed\n" );
9206     ok_sequence( WmUser, "WmUser", FALSE );
9207
9208     info.timeout = 0x80000000;
9209     info.ret = 0xdeadbeef;
9210     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9211     Sleep(100);
9212     wait_for_thread( thread );
9213     CloseHandle( thread );
9214     if (is_win9x)
9215     {
9216         ok( info.ret == 1, "SendMessageTimeout failed\n" );
9217         ok_sequence( WmUser, "WmUser", FALSE );
9218     }
9219     else
9220     {
9221         ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
9222         ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
9223     }
9224
9225     /* now check for timeout during message processing */
9226     SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
9227     info.timeout = 100;
9228     info.ret = 0xdeadbeef;
9229     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9230     wait_for_thread( thread );
9231     CloseHandle( thread );
9232     /* we should time out but still get the message */
9233     ok( info.ret == 0, "SendMessageTimeout failed\n" );
9234     ok_sequence( WmUser, "WmUser", FALSE );
9235
9236     DestroyWindow( info.hwnd );
9237 }
9238
9239
9240 /****************** edit message test *************************/
9241 #define ID_EDIT 0x1234
9242 static const struct message sl_edit_setfocus[] =
9243 {
9244     { HCBT_SETFOCUS, hook },
9245     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
9246     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9247     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9248     { WM_SETFOCUS, sent|wparam, 0 },
9249     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
9250     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 },
9251     { WM_CTLCOLOREDIT, sent|parent },
9252     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9253     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9254     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9255     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
9256     { 0 }
9257 };
9258 static const struct message ml_edit_setfocus[] =
9259 {
9260     { HCBT_SETFOCUS, hook },
9261     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
9262     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9263     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9264     { WM_SETFOCUS, sent|wparam, 0 },
9265     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
9266     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9267     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9268     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9269     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
9270     { 0 }
9271 };
9272 static const struct message sl_edit_killfocus[] =
9273 {
9274     { HCBT_SETFOCUS, hook },
9275     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9276     { WM_KILLFOCUS, sent|wparam, 0 },
9277     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9278     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9279     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
9280     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
9281     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
9282     { 0 }
9283 };
9284 static const struct message sl_edit_lbutton_dblclk[] =
9285 {
9286     { WM_LBUTTONDBLCLK, sent },
9287     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
9288     { 0 }
9289 };
9290 static const struct message sl_edit_lbutton_down[] =
9291 {
9292     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
9293     { HCBT_SETFOCUS, hook },
9294     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
9295     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9296     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9297     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
9298     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
9299     { WM_CTLCOLOREDIT, sent|parent },
9300     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9301     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9302     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9303     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9304     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
9305     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
9306     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9307     { WM_CTLCOLOREDIT, sent|parent|optional },
9308     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9309     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9310     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9311     { 0 }
9312 };
9313 static const struct message ml_edit_lbutton_down[] =
9314 {
9315     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
9316     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
9317     { HCBT_SETFOCUS, hook },
9318     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
9319     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9320     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9321     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
9322     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
9323     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9324     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9325     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9326     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
9327     { 0 }
9328 };
9329 static const struct message sl_edit_lbutton_up[] =
9330 {
9331     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
9332     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9333     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
9334     { WM_CAPTURECHANGED, sent|defwinproc },
9335     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9336     { 0 }
9337 };
9338 static const struct message ml_edit_lbutton_up[] =
9339 {
9340     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
9341     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
9342     { WM_CAPTURECHANGED, sent|defwinproc },
9343     { 0 }
9344 };
9345
9346 static WNDPROC old_edit_proc;
9347
9348 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9349 {
9350     static LONG defwndproc_counter = 0;
9351     LRESULT ret;
9352     struct recvd_message msg;
9353
9354     if (ignore_message( message )) return 0;
9355
9356     msg.hwnd = hwnd;
9357     msg.message = message;
9358     msg.flags = sent|wparam|lparam;
9359     if (defwndproc_counter) msg.flags |= defwinproc;
9360     msg.wParam = wParam;
9361     msg.lParam = lParam;
9362     msg.descr = "edit";
9363     add_message(&msg);
9364
9365     defwndproc_counter++;
9366     ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
9367     defwndproc_counter--;
9368
9369     return ret;
9370 }
9371
9372 static void subclass_edit(void)
9373 {
9374     WNDCLASSA cls;
9375
9376     if (!GetClassInfoA(0, "edit", &cls)) assert(0);
9377
9378     old_edit_proc = cls.lpfnWndProc;
9379
9380     cls.hInstance = GetModuleHandle(0);
9381     cls.lpfnWndProc = edit_hook_proc;
9382     cls.lpszClassName = "my_edit_class";
9383     UnregisterClass(cls.lpszClassName, cls.hInstance);
9384     if (!RegisterClassA(&cls)) assert(0);
9385 }
9386
9387 static void test_edit_messages(void)
9388 {
9389     HWND hwnd, parent;
9390     DWORD dlg_code;
9391
9392     subclass_edit();
9393     log_all_parent_messages++;
9394
9395     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9396                              100, 100, 200, 200, 0, 0, 0, NULL);
9397     ok (parent != 0, "Failed to create parent window\n");
9398
9399     /* test single line edit */
9400     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
9401                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
9402     ok(hwnd != 0, "Failed to create edit window\n");
9403
9404     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
9405     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
9406
9407     ShowWindow(hwnd, SW_SHOW);
9408     UpdateWindow(hwnd);
9409     SetFocus(0);
9410     flush_sequence();
9411
9412     SetFocus(hwnd);
9413     ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
9414
9415     SetFocus(0);
9416     ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
9417
9418     SetFocus(0);
9419     ReleaseCapture();
9420     flush_sequence();
9421
9422     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
9423     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
9424
9425     SetFocus(0);
9426     ReleaseCapture();
9427     flush_sequence();
9428
9429     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
9430     ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
9431
9432     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
9433     ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
9434
9435     DestroyWindow(hwnd);
9436
9437     /* test multiline edit */
9438     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
9439                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
9440     ok(hwnd != 0, "Failed to create edit window\n");
9441
9442     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
9443     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
9444        "wrong dlg_code %08x\n", dlg_code);
9445
9446     ShowWindow(hwnd, SW_SHOW);
9447     UpdateWindow(hwnd);
9448     SetFocus(0);
9449     flush_sequence();
9450
9451     SetFocus(hwnd);
9452     ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
9453
9454     SetFocus(0);
9455     ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
9456
9457     SetFocus(0);
9458     ReleaseCapture();
9459     flush_sequence();
9460
9461     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
9462     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
9463
9464     SetFocus(0);
9465     ReleaseCapture();
9466     flush_sequence();
9467
9468     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
9469     ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
9470
9471     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
9472     ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
9473
9474     DestroyWindow(hwnd);
9475     DestroyWindow(parent);
9476
9477     log_all_parent_messages--;
9478 }
9479
9480 /**************************** End of Edit test ******************************/
9481
9482 static const struct message WmKeyDownSkippedSeq[] =
9483 {
9484     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
9485     { 0 }
9486 };
9487 static const struct message WmKeyDownWasDownSkippedSeq[] =
9488 {
9489     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x40000001 }, /* XP */
9490     { 0 }
9491 };
9492 static const struct message WmKeyUpSkippedSeq[] =
9493 {
9494     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9495     { 0 }
9496 };
9497 static const struct message WmUserKeyUpSkippedSeq[] =
9498 {
9499     { WM_USER, sent },
9500     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9501     { 0 }
9502 };
9503
9504 #define EV_STOP 0
9505 #define EV_SENDMSG 1
9506 #define EV_ACK 2
9507
9508 struct peekmsg_info
9509 {
9510     HWND  hwnd;
9511     HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
9512 };
9513
9514 static DWORD CALLBACK send_msg_thread_2(void *param)
9515 {
9516     DWORD ret;
9517     struct peekmsg_info *info = param;
9518
9519     trace("thread: looping\n");
9520     SetEvent(info->hevent[EV_ACK]);
9521
9522     while (1)
9523     {
9524         ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
9525
9526         switch (ret)
9527         {
9528         case WAIT_OBJECT_0 + EV_STOP:
9529             trace("thread: exiting\n");
9530             return 0;
9531
9532         case WAIT_OBJECT_0 + EV_SENDMSG:
9533             trace("thread: sending message\n");
9534             ret = SendNotifyMessageA(info->hwnd, WM_USER, 0, 0);
9535             ok(ret, "SendNotifyMessageA failed error %u\n", GetLastError());
9536             SetEvent(info->hevent[EV_ACK]);
9537             break;
9538
9539         default:
9540             trace("unexpected return: %04x\n", ret);
9541             assert(0);
9542             break;
9543         }
9544     }
9545     return 0;
9546 }
9547
9548 static void test_PeekMessage(void)
9549 {
9550     MSG msg;
9551     HANDLE hthread;
9552     DWORD tid, qstatus;
9553     UINT qs_all_input = QS_ALLINPUT;
9554     UINT qs_input = QS_INPUT;
9555     BOOL ret;
9556     struct peekmsg_info info;
9557
9558     info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
9559                               100, 100, 200, 200, 0, 0, 0, NULL);
9560     assert(info.hwnd);
9561     ShowWindow(info.hwnd, SW_SHOW);
9562     UpdateWindow(info.hwnd);
9563     SetFocus(info.hwnd);
9564
9565     info.hevent[EV_STOP] = CreateEventA(NULL, 0, 0, NULL);
9566     info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
9567     info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
9568
9569     hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
9570     WaitForSingleObject(info.hevent[EV_ACK], 10000);
9571
9572     flush_events();
9573     flush_sequence();
9574
9575     SetLastError(0xdeadbeef);
9576     qstatus = GetQueueStatus(qs_all_input);
9577     if (GetLastError() == ERROR_INVALID_FLAGS)
9578     {
9579         trace("QS_RAWINPUT not supported on this platform\n");
9580         qs_all_input &= ~QS_RAWINPUT;
9581         qs_input &= ~QS_RAWINPUT;
9582     }
9583     if (qstatus & QS_POSTMESSAGE)
9584     {
9585         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) /* nothing */ ;
9586         qstatus = GetQueueStatus(qs_all_input);
9587     }
9588     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9589
9590     trace("signalling to send message\n");
9591     SetEvent(info.hevent[EV_SENDMSG]);
9592     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9593
9594     /* pass invalid QS_xxxx flags */
9595     SetLastError(0xdeadbeef);
9596     qstatus = GetQueueStatus(0xffffffff);
9597     ok(qstatus == 0 || broken(qstatus)  /* win9x */, "GetQueueStatus should fail: %08x\n", qstatus);
9598     if (!qstatus)
9599     {
9600         ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
9601         qstatus = GetQueueStatus(qs_all_input);
9602     }
9603     qstatus &= ~MAKELONG( 0x4000, 0x4000 );  /* sometimes set on Win95 */
9604     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
9605        "wrong qstatus %08x\n", qstatus);
9606
9607     msg.message = 0;
9608     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9609     ok(!ret,
9610        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9611         msg.message);
9612     ok_sequence(WmUser, "WmUser", FALSE);
9613
9614     qstatus = GetQueueStatus(qs_all_input);
9615     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9616
9617     keybd_event('N', 0, 0, 0);
9618     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9619     qstatus = GetQueueStatus(qs_all_input);
9620     if (!(qstatus & MAKELONG(QS_KEY, QS_KEY)))
9621     {
9622         skip( "queuing key events not supported\n" );
9623         goto done;
9624     }
9625     ok(qstatus == MAKELONG(QS_KEY, QS_KEY) ||
9626        /* keybd_event seems to trigger a sent message on NT4 */
9627        qstatus == MAKELONG(QS_KEY|QS_SENDMESSAGE, QS_KEY|QS_SENDMESSAGE),
9628        "wrong qstatus %08x\n", qstatus);
9629
9630     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9631     qstatus = GetQueueStatus(qs_all_input);
9632     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY) ||
9633        qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
9634        "wrong qstatus %08x\n", qstatus);
9635
9636     InvalidateRect(info.hwnd, NULL, FALSE);
9637     qstatus = GetQueueStatus(qs_all_input);
9638     ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY) ||
9639        qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
9640        "wrong qstatus %08x\n", qstatus);
9641
9642     trace("signalling to send message\n");
9643     SetEvent(info.hevent[EV_SENDMSG]);
9644     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9645
9646     qstatus = GetQueueStatus(qs_all_input);
9647     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9648        "wrong qstatus %08x\n", qstatus);
9649
9650     msg.message = 0;
9651     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
9652     if (ret && msg.message == WM_CHAR)
9653     {
9654         win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
9655         goto done;
9656     }
9657     ok(!ret,
9658        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9659         msg.message);
9660     if (!sequence_cnt)  /* nt4 doesn't fetch anything with PM_QS_* flags */
9661     {
9662         win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
9663         goto done;
9664     }
9665     ok_sequence(WmUser, "WmUser", FALSE);
9666
9667     qstatus = GetQueueStatus(qs_all_input);
9668     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9669        "wrong qstatus %08x\n", qstatus);
9670
9671     trace("signalling to send message\n");
9672     SetEvent(info.hevent[EV_SENDMSG]);
9673     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9674
9675     qstatus = GetQueueStatus(qs_all_input);
9676     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9677        "wrong qstatus %08x\n", qstatus);
9678
9679     msg.message = 0;
9680     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE );
9681     ok(!ret,
9682        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9683         msg.message);
9684     ok_sequence(WmUser, "WmUser", FALSE);
9685
9686     qstatus = GetQueueStatus(qs_all_input);
9687     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9688        "wrong qstatus %08x\n", qstatus);
9689
9690     msg.message = 0;
9691     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
9692     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9693        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9694        ret, msg.message, msg.wParam);
9695     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9696
9697     qstatus = GetQueueStatus(qs_all_input);
9698     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
9699        "wrong qstatus %08x\n", qstatus);
9700
9701     msg.message = 0;
9702     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
9703     ok(!ret,
9704        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9705         msg.message);
9706     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9707
9708     qstatus = GetQueueStatus(qs_all_input);
9709     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
9710        "wrong qstatus %08x\n", qstatus);
9711
9712     msg.message = 0;
9713     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
9714     ok(ret && msg.message == WM_PAINT,
9715        "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
9716     DispatchMessageA(&msg);
9717     ok_sequence(WmPaint, "WmPaint", FALSE);
9718
9719     qstatus = GetQueueStatus(qs_all_input);
9720     ok(qstatus == MAKELONG(0, QS_KEY),
9721        "wrong qstatus %08x\n", qstatus);
9722
9723     msg.message = 0;
9724     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
9725     ok(!ret,
9726        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9727         msg.message);
9728     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9729
9730     qstatus = GetQueueStatus(qs_all_input);
9731     ok(qstatus == MAKELONG(0, QS_KEY),
9732        "wrong qstatus %08x\n", qstatus);
9733
9734     trace("signalling to send message\n");
9735     SetEvent(info.hevent[EV_SENDMSG]);
9736     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9737
9738     qstatus = GetQueueStatus(qs_all_input);
9739     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
9740        "wrong qstatus %08x\n", qstatus);
9741
9742     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9743
9744     qstatus = GetQueueStatus(qs_all_input);
9745     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9746        "wrong qstatus %08x\n", qstatus);
9747
9748     msg.message = 0;
9749     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
9750     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9751        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9752        ret, msg.message, msg.wParam);
9753     ok_sequence(WmUser, "WmUser", FALSE);
9754
9755     qstatus = GetQueueStatus(qs_all_input);
9756     ok(qstatus == MAKELONG(0, QS_KEY),
9757        "wrong qstatus %08x\n", qstatus);
9758
9759     msg.message = 0;
9760     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
9761     ok(!ret,
9762        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9763         msg.message);
9764     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9765
9766     qstatus = GetQueueStatus(qs_all_input);
9767     ok(qstatus == MAKELONG(0, QS_KEY),
9768        "wrong qstatus %08x\n", qstatus);
9769
9770     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9771
9772     qstatus = GetQueueStatus(qs_all_input);
9773     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
9774        "wrong qstatus %08x\n", qstatus);
9775
9776     trace("signalling to send message\n");
9777     SetEvent(info.hevent[EV_SENDMSG]);
9778     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9779
9780     qstatus = GetQueueStatus(qs_all_input);
9781     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9782        "wrong qstatus %08x\n", qstatus);
9783
9784     msg.message = 0;
9785     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
9786     ok(!ret,
9787        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9788         msg.message);
9789     ok_sequence(WmUser, "WmUser", FALSE);
9790
9791     qstatus = GetQueueStatus(qs_all_input);
9792     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
9793        "wrong qstatus %08x\n", qstatus);
9794
9795     msg.message = 0;
9796     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
9797         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
9798     else /* workaround for a missing QS_RAWINPUT support */
9799         ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
9800     ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9801        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9802        ret, msg.message, msg.wParam);
9803     ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
9804
9805     qstatus = GetQueueStatus(qs_all_input);
9806     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
9807        "wrong qstatus %08x\n", qstatus);
9808
9809     msg.message = 0;
9810     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
9811         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
9812     else /* workaround for a missing QS_RAWINPUT support */
9813         ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
9814     ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
9815        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYUP wParam 'N'\n",
9816        ret, msg.message, msg.wParam);
9817     ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
9818
9819     qstatus = GetQueueStatus(qs_all_input);
9820     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9821        "wrong qstatus %08x\n", qstatus);
9822
9823     msg.message = 0;
9824     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
9825     ok(!ret,
9826        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9827         msg.message);
9828     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9829
9830     qstatus = GetQueueStatus(qs_all_input);
9831     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9832        "wrong qstatus %08x\n", qstatus);
9833
9834     msg.message = 0;
9835     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9836     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9837        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9838        ret, msg.message, msg.wParam);
9839     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9840
9841     qstatus = GetQueueStatus(qs_all_input);
9842     ok(qstatus == 0,
9843        "wrong qstatus %08x\n", qstatus);
9844
9845     msg.message = 0;
9846     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9847     ok(!ret,
9848        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9849         msg.message);
9850     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9851
9852     qstatus = GetQueueStatus(qs_all_input);
9853     ok(qstatus == 0,
9854        "wrong qstatus %08x\n", qstatus);
9855
9856     /* test whether presence of the quit flag in the queue affects
9857      * the queue state
9858      */
9859     PostQuitMessage(0x1234abcd);
9860
9861     qstatus = GetQueueStatus(qs_all_input);
9862     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
9863        "wrong qstatus %08x\n", qstatus);
9864
9865     PostMessageA(info.hwnd, WM_USER, 0, 0);
9866
9867     qstatus = GetQueueStatus(qs_all_input);
9868     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
9869        "wrong qstatus %08x\n", qstatus);
9870
9871     msg.message = 0;
9872     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9873     ok(ret && msg.message == WM_USER,
9874        "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
9875     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9876
9877     qstatus = GetQueueStatus(qs_all_input);
9878     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9879        "wrong qstatus %08x\n", qstatus);
9880
9881     msg.message = 0;
9882     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9883     ok(ret && msg.message == WM_QUIT,
9884        "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
9885     ok(msg.wParam == 0x1234abcd, "got wParam %08lx instead of 0x1234abcd\n", msg.wParam);
9886     ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
9887     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9888
9889     qstatus = GetQueueStatus(qs_all_input);
9890 todo_wine {
9891     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9892        "wrong qstatus %08x\n", qstatus);
9893 }
9894
9895     msg.message = 0;
9896     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9897     ok(!ret,
9898        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9899         msg.message);
9900     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9901
9902     qstatus = GetQueueStatus(qs_all_input);
9903     ok(qstatus == 0,
9904        "wrong qstatus %08x\n", qstatus);
9905
9906     /* some GetMessage tests */
9907
9908     keybd_event('N', 0, 0, 0);
9909     qstatus = GetQueueStatus(qs_all_input);
9910     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9911
9912     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9913     qstatus = GetQueueStatus(qs_all_input);
9914     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9915
9916     if (qstatus)
9917     {
9918         ret = GetMessageA( &msg, 0, 0, 0 );
9919         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9920            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9921            ret, msg.message, msg.wParam);
9922         qstatus = GetQueueStatus(qs_all_input);
9923         ok(qstatus == MAKELONG(0, QS_KEY), "wrong qstatus %08x\n", qstatus);
9924     }
9925
9926     if (qstatus)
9927     {
9928         ret = GetMessageA( &msg, 0, 0, 0 );
9929         ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9930            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9931            ret, msg.message, msg.wParam);
9932         ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
9933         qstatus = GetQueueStatus(qs_all_input);
9934         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9935     }
9936
9937     keybd_event('N', 0, 0, 0);
9938     qstatus = GetQueueStatus(qs_all_input);
9939     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9940
9941     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9942     qstatus = GetQueueStatus(qs_all_input);
9943     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9944
9945     if (qstatus & (QS_KEY << 16))
9946     {
9947         ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
9948         ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9949            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9950            ret, msg.message, msg.wParam);
9951         ok_sequence(WmKeyDownWasDownSkippedSeq, "WmKeyDownWasDownSkippedSeq", FALSE);
9952         qstatus = GetQueueStatus(qs_all_input);
9953         ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
9954     }
9955
9956     if (qstatus)
9957     {
9958         ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
9959         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9960            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9961            ret, msg.message, msg.wParam);
9962         qstatus = GetQueueStatus(qs_all_input);
9963         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9964     }
9965
9966     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9967     qstatus = GetQueueStatus(qs_all_input);
9968     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9969
9970     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9971     qstatus = GetQueueStatus(qs_all_input);
9972     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9973
9974     trace("signalling to send message\n");
9975     SetEvent(info.hevent[EV_SENDMSG]);
9976     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9977     qstatus = GetQueueStatus(qs_all_input);
9978     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9979        "wrong qstatus %08x\n", qstatus);
9980
9981     if (qstatus & (QS_KEY << 16))
9982     {
9983         ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
9984         ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
9985            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9986            ret, msg.message, msg.wParam);
9987         ok_sequence(WmUserKeyUpSkippedSeq, "WmUserKeyUpSkippedSeq", FALSE);
9988         qstatus = GetQueueStatus(qs_all_input);
9989         ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
9990     }
9991
9992     if (qstatus)
9993     {
9994         ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
9995         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9996            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9997            ret, msg.message, msg.wParam);
9998         qstatus = GetQueueStatus(qs_all_input);
9999         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
10000     }
10001 done:
10002     trace("signalling to exit\n");
10003     SetEvent(info.hevent[EV_STOP]);
10004
10005     WaitForSingleObject(hthread, INFINITE);
10006
10007     CloseHandle(hthread);
10008     CloseHandle(info.hevent[0]);
10009     CloseHandle(info.hevent[1]);
10010     CloseHandle(info.hevent[2]);
10011
10012     DestroyWindow(info.hwnd);
10013 }
10014
10015 static void wait_move_event(HWND hwnd, int x, int y)
10016 {
10017     MSG msg;
10018     DWORD time;
10019     BOOL  ret;
10020     int go = 0;
10021
10022     time = GetTickCount();
10023     while (GetTickCount() - time < 200 && !go) {
10024         ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
10025         go  = ret && msg.pt.x > x && msg.pt.y > y;
10026         if (!ret) MsgWaitForMultipleObjects( 0, NULL, FALSE, GetTickCount() - time, QS_ALLINPUT );
10027     }
10028 }
10029
10030 #define STEP 5
10031 static void test_PeekMessage2(void)
10032 {
10033     HWND hwnd;
10034     BOOL ret;
10035     MSG msg;
10036     UINT message;
10037     DWORD time1, time2, time3;
10038     int x1, y1, x2, y2, x3, y3;
10039     POINT pos;
10040
10041     time1 = time2 = time3 = 0;
10042     x1 = y1 = x2 = y2 = x3 = y3 = 0;
10043
10044     /* Initialise window and make sure it is ready for events */
10045     hwnd = CreateWindow("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
10046                         10, 10, 800, 800, NULL, NULL, NULL, NULL);
10047     assert(hwnd);
10048     trace("Window for test_PeekMessage2 %p\n", hwnd);
10049     ShowWindow(hwnd, SW_SHOW);
10050     UpdateWindow(hwnd);
10051     SetFocus(hwnd);
10052     GetCursorPos(&pos);
10053     SetCursorPos(100, 100);
10054     mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
10055     flush_events();
10056
10057     /* Do initial mousemove, wait until we can see it
10058        and then do our test peek with PM_NOREMOVE. */
10059     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
10060     wait_move_event(hwnd, 100-STEP, 100-STEP);
10061
10062     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
10063     if (!ret)
10064     {
10065         skip( "queuing mouse events not supported\n" );
10066         goto done;
10067     }
10068     else
10069     {
10070         trace("1st move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
10071         message = msg.message;
10072         time1 = msg.time;
10073         x1 = msg.pt.x;
10074         y1 = msg.pt.y;
10075         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
10076     }
10077
10078     /* Allow time to advance a bit, and then simulate the user moving their
10079      * mouse around. After that we peek again with PM_NOREMOVE.
10080      * Although the previous mousemove message was never removed, the
10081      * mousemove we now peek should reflect the recent mouse movements
10082      * because the input queue will merge the move events. */
10083     Sleep(100);
10084     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
10085     wait_move_event(hwnd, x1, y1);
10086
10087     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
10088     ok(ret, "no message available\n");
10089     if (ret) {
10090         trace("2nd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
10091         message = msg.message;
10092         time2 = msg.time;
10093         x2 = msg.pt.x;
10094         y2 = msg.pt.y;
10095         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
10096         ok(time2 > time1, "message time not advanced: %x %x\n", time1, time2);
10097         ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
10098     }
10099
10100     /* Have another go, to drive the point home */
10101     Sleep(100);
10102     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
10103     wait_move_event(hwnd, x2, y2);
10104
10105     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
10106     ok(ret, "no message available\n");
10107     if (ret) {
10108         trace("3rd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
10109         message = msg.message;
10110         time3 = msg.time;
10111         x3 = msg.pt.x;
10112         y3 = msg.pt.y;
10113         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
10114         ok(time3 > time2, "message time not advanced: %x %x\n", time2, time3);
10115         ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
10116     }
10117
10118 done:
10119     DestroyWindow(hwnd);
10120     SetCursorPos(pos.x, pos.y);
10121     flush_events();
10122 }
10123
10124 static INT_PTR CALLBACK wm_quit_dlg_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
10125 {
10126     struct recvd_message msg;
10127
10128     if (ignore_message( message )) return 0;
10129
10130     msg.hwnd = hwnd;
10131     msg.message = message;
10132     msg.flags = sent|wparam|lparam;
10133     msg.wParam = wp;
10134     msg.lParam = lp;
10135     msg.descr = "dialog";
10136     add_message(&msg);
10137
10138     switch (message)
10139     {
10140     case WM_INITDIALOG:
10141         PostMessage(hwnd, WM_QUIT, 0x1234, 0x5678);
10142         PostMessage(hwnd, WM_USER, 0xdead, 0xbeef);
10143         return 0;
10144
10145     case WM_GETDLGCODE:
10146         return 0;
10147
10148     case WM_USER:
10149         EndDialog(hwnd, 0);
10150         break;
10151     }
10152
10153     return 1;
10154 }
10155
10156 static const struct message WmQuitDialogSeq[] = {
10157     { HCBT_CREATEWND, hook },
10158     { WM_SETFONT, sent },
10159     { WM_INITDIALOG, sent },
10160     { WM_CHANGEUISTATE, sent|optional },
10161     { HCBT_DESTROYWND, hook },
10162     { 0x0090, sent|optional }, /* Vista */
10163     { WM_DESTROY, sent },
10164     { WM_NCDESTROY, sent },
10165     { 0 }
10166 };
10167
10168 static const struct message WmStopQuitSeq[] = {
10169     { WM_DWMNCRENDERINGCHANGED, posted|optional },
10170     { WM_CLOSE, posted },
10171     { WM_QUIT, posted|wparam|lparam, 0x1234, 0 },
10172     { 0 }
10173 };
10174
10175 static void test_quit_message(void)
10176 {
10177     MSG msg;
10178     BOOL ret;
10179
10180     /* test using PostQuitMessage */
10181     flush_events();
10182     PostQuitMessage(0xbeef);
10183
10184     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
10185     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
10186     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10187     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
10188
10189     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
10190     ok(ret, "PostMessage failed with error %d\n", GetLastError());
10191
10192     ret = GetMessage(&msg, NULL, 0, 0);
10193     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
10194     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
10195
10196     /* note: WM_QUIT message received after WM_USER message */
10197     ret = GetMessage(&msg, NULL, 0, 0);
10198     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
10199     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10200     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
10201
10202     ret = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
10203     ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
10204
10205     /* now test with PostThreadMessage - different behaviour! */
10206     PostThreadMessage(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
10207
10208     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
10209     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
10210     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10211     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
10212
10213     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
10214     ok(ret, "PostMessage failed with error %d\n", GetLastError());
10215
10216     /* note: we receive the WM_QUIT message first this time */
10217     ret = GetMessage(&msg, NULL, 0, 0);
10218     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
10219     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10220     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
10221
10222     ret = GetMessage(&msg, NULL, 0, 0);
10223     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
10224     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
10225
10226     flush_events();
10227     flush_sequence();
10228     ret = DialogBoxParam(GetModuleHandle(0), "TEST_EMPTY_DIALOG", 0, wm_quit_dlg_proc, 0);
10229     ok(ret == 1, "expected 1, got %d\n", ret);
10230     ok_sequence(WmQuitDialogSeq, "WmQuitDialogSeq", FALSE);
10231     memset(&msg, 0xab, sizeof(msg));
10232     ret = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
10233     ok(ret, "PeekMessage failed\n");
10234     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10235     ok(msg.wParam == 0x1234, "wParam was 0x%lx instead of 0x1234\n", msg.wParam);
10236     ok(msg.lParam == 0, "lParam was 0x%lx instead of 0\n", msg.lParam);
10237
10238     /* Check what happens to a WM_QUIT message posted to a window that gets
10239      * destroyed.
10240      */
10241     CreateWindowExA(0, "StopQuitClass", "Stop Quit Test", WS_OVERLAPPEDWINDOW,
10242                     0, 0, 100, 100, NULL, NULL, NULL, NULL);
10243     flush_sequence();
10244     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
10245     {
10246         struct recvd_message rmsg;
10247         rmsg.hwnd = msg.hwnd;
10248         rmsg.message = msg.message;
10249         rmsg.flags = posted|wparam|lparam;
10250         rmsg.wParam = msg.wParam;
10251         rmsg.lParam = msg.lParam;
10252         rmsg.descr = "stop/quit";
10253         if (msg.message == WM_QUIT)
10254             /* The hwnd can only be checked here */
10255             ok(!msg.hwnd, "The WM_QUIT hwnd was %p instead of NULL\n", msg.hwnd);
10256         add_message(&rmsg);
10257         DispatchMessage(&msg);
10258     }
10259     ok_sequence(WmStopQuitSeq, "WmStopQuitSeq", FALSE);
10260 }
10261
10262 static const struct message WmMouseHoverSeq[] = {
10263     { WM_MOUSEACTIVATE, sent|optional },  /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
10264     { WM_MOUSEACTIVATE, sent|optional },
10265     { WM_TIMER, sent|optional }, /* XP sends it */
10266     { WM_SYSTIMER, sent },
10267     { WM_MOUSEHOVER, sent|wparam, 0 },
10268     { 0 }
10269 };
10270
10271 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
10272 {
10273     MSG msg;
10274     DWORD start_ticks, end_ticks;
10275
10276     start_ticks = GetTickCount();
10277     /* add some deviation (50%) to cover not expected delays */
10278     start_ticks += timeout / 2;
10279
10280     do
10281     {
10282         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
10283         {
10284             /* Timer proc messages are not dispatched to the window proc,
10285              * and therefore not logged.
10286              */
10287             if ((msg.message == WM_TIMER || msg.message == WM_SYSTIMER) && msg.hwnd)
10288             {
10289                 struct recvd_message s_msg;
10290
10291                 s_msg.hwnd = msg.hwnd;
10292                 s_msg.message = msg.message;
10293                 s_msg.flags = sent|wparam|lparam;
10294                 s_msg.wParam = msg.wParam;
10295                 s_msg.lParam = msg.lParam;
10296                 s_msg.descr = "msg_loop";
10297                 add_message(&s_msg);
10298             }
10299             DispatchMessage(&msg);
10300         }
10301
10302         end_ticks = GetTickCount();
10303
10304         /* inject WM_MOUSEMOVE to see how it changes tracking */
10305         if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
10306         {
10307             mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10308             mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10309
10310             inject_mouse_move = FALSE;
10311         }
10312     } while (start_ticks + timeout >= end_ticks);
10313 }
10314
10315 static void test_TrackMouseEvent(void)
10316 {
10317     TRACKMOUSEEVENT tme;
10318     BOOL ret;
10319     HWND hwnd, hchild;
10320     RECT rc_parent, rc_child;
10321     UINT default_hover_time, hover_width = 0, hover_height = 0;
10322
10323 #define track_hover(track_hwnd, track_hover_time) \
10324     tme.cbSize = sizeof(tme); \
10325     tme.dwFlags = TME_HOVER; \
10326     tme.hwndTrack = track_hwnd; \
10327     tme.dwHoverTime = track_hover_time; \
10328     SetLastError(0xdeadbeef); \
10329     ret = pTrackMouseEvent(&tme); \
10330     ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
10331
10332 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
10333     tme.cbSize = sizeof(tme); \
10334     tme.dwFlags = TME_QUERY; \
10335     tme.hwndTrack = (HWND)0xdeadbeef; \
10336     tme.dwHoverTime = 0xdeadbeef; \
10337     SetLastError(0xdeadbeef); \
10338     ret = pTrackMouseEvent(&tme); \
10339     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
10340     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
10341     ok(tme.dwFlags == (expected_track_flags), \
10342        "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
10343     ok(tme.hwndTrack == (expected_track_hwnd), \
10344        "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
10345     ok(tme.dwHoverTime == (expected_hover_time), \
10346        "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
10347
10348 #define track_hover_cancel(track_hwnd) \
10349     tme.cbSize = sizeof(tme); \
10350     tme.dwFlags = TME_HOVER | TME_CANCEL; \
10351     tme.hwndTrack = track_hwnd; \
10352     tme.dwHoverTime = 0xdeadbeef; \
10353     SetLastError(0xdeadbeef); \
10354     ret = pTrackMouseEvent(&tme); \
10355     ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
10356
10357     default_hover_time = 0xdeadbeef;
10358     SetLastError(0xdeadbeef);
10359     ret = SystemParametersInfo(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
10360     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
10361        "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
10362     if (!ret) default_hover_time = 400;
10363     trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
10364
10365     SetLastError(0xdeadbeef);
10366     ret = SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
10367     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
10368        "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
10369     if (!ret) hover_width = 4;
10370     SetLastError(0xdeadbeef);
10371     ret = SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
10372     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
10373        "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
10374     if (!ret) hover_height = 4;
10375     trace("hover rect is %u x %d\n", hover_width, hover_height);
10376
10377     hwnd = CreateWindowEx(0, "TestWindowClass", NULL,
10378                           WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10379                           CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
10380                           NULL, NULL, 0);
10381     assert(hwnd);
10382
10383     hchild = CreateWindowEx(0, "TestWindowClass", NULL,
10384                           WS_CHILD | WS_BORDER | WS_VISIBLE,
10385                           50, 50, 200, 200, hwnd,
10386                           NULL, NULL, 0);
10387     assert(hchild);
10388
10389     SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
10390     flush_events();
10391     flush_sequence();
10392
10393     tme.cbSize = 0;
10394     tme.dwFlags = TME_QUERY;
10395     tme.hwndTrack = (HWND)0xdeadbeef;
10396     tme.dwHoverTime = 0xdeadbeef;
10397     SetLastError(0xdeadbeef);
10398     ret = pTrackMouseEvent(&tme);
10399     ok(!ret, "TrackMouseEvent should fail\n");
10400     ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef),
10401        "not expected error %u\n", GetLastError());
10402
10403     tme.cbSize = sizeof(tme);
10404     tme.dwFlags = TME_HOVER;
10405     tme.hwndTrack = (HWND)0xdeadbeef;
10406     tme.dwHoverTime = 0xdeadbeef;
10407     SetLastError(0xdeadbeef);
10408     ret = pTrackMouseEvent(&tme);
10409     ok(!ret, "TrackMouseEvent should fail\n");
10410     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
10411        "not expected error %u\n", GetLastError());
10412
10413     tme.cbSize = sizeof(tme);
10414     tme.dwFlags = TME_HOVER | TME_CANCEL;
10415     tme.hwndTrack = (HWND)0xdeadbeef;
10416     tme.dwHoverTime = 0xdeadbeef;
10417     SetLastError(0xdeadbeef);
10418     ret = pTrackMouseEvent(&tme);
10419     ok(!ret, "TrackMouseEvent should fail\n");
10420     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
10421        "not expected error %u\n", GetLastError());
10422
10423     GetWindowRect(hwnd, &rc_parent);
10424     GetWindowRect(hchild, &rc_child);
10425     SetCursorPos(rc_child.left - 10, rc_child.top - 10);
10426
10427     /* Process messages so that the system updates its internal current
10428      * window and hittest, otherwise TrackMouseEvent calls don't have any
10429      * effect.
10430      */
10431     flush_events();
10432     flush_sequence();
10433
10434     track_query(0, NULL, 0);
10435     track_hover(hchild, 0);
10436     track_query(0, NULL, 0);
10437
10438     flush_events();
10439     flush_sequence();
10440
10441     track_hover(hwnd, 0);
10442     tme.cbSize = sizeof(tme);
10443     tme.dwFlags = TME_QUERY;
10444     tme.hwndTrack = (HWND)0xdeadbeef;
10445     tme.dwHoverTime = 0xdeadbeef;
10446     SetLastError(0xdeadbeef);
10447     ret = pTrackMouseEvent(&tme);
10448     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());
10449     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize);
10450     if (!tme.dwFlags)
10451     {
10452         skip( "Cursor not inside window, skipping TrackMouseEvent tests\n" );
10453         DestroyWindow( hwnd );
10454         return;
10455     }
10456     ok(tme.dwFlags == TME_HOVER, "wrong tme.dwFlags %08x, expected TME_HOVER\n", tme.dwFlags);
10457     ok(tme.hwndTrack == hwnd, "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, hwnd);
10458     ok(tme.dwHoverTime == default_hover_time, "wrong tme.dwHoverTime %u, expected %u\n",
10459        tme.dwHoverTime, default_hover_time);
10460
10461     pump_msg_loop_timeout(default_hover_time, FALSE);
10462     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
10463
10464     track_query(0, NULL, 0);
10465
10466     track_hover(hwnd, HOVER_DEFAULT);
10467     track_query(TME_HOVER, hwnd, default_hover_time);
10468
10469     Sleep(default_hover_time / 2);
10470     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10471     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10472
10473     track_query(TME_HOVER, hwnd, default_hover_time);
10474
10475     pump_msg_loop_timeout(default_hover_time, FALSE);
10476     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
10477
10478     track_query(0, NULL, 0);
10479
10480     track_hover(hwnd, HOVER_DEFAULT);
10481     track_query(TME_HOVER, hwnd, default_hover_time);
10482
10483     pump_msg_loop_timeout(default_hover_time, TRUE);
10484     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
10485
10486     track_query(0, NULL, 0);
10487
10488     track_hover(hwnd, HOVER_DEFAULT);
10489     track_query(TME_HOVER, hwnd, default_hover_time);
10490     track_hover_cancel(hwnd);
10491
10492     DestroyWindow(hwnd);
10493
10494 #undef track_hover
10495 #undef track_query
10496 #undef track_hover_cancel
10497 }
10498
10499
10500 static const struct message WmSetWindowRgn[] = {
10501     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10502     { WM_NCCALCSIZE, sent|wparam, 1 },
10503     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
10504     { WM_GETTEXT, sent|defwinproc|optional },
10505     { WM_ERASEBKGND, sent|optional },
10506     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10507     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10508     { 0 }
10509 };
10510
10511 static const struct message WmSetWindowRgn_no_redraw[] = {
10512     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
10513     { WM_NCCALCSIZE, sent|wparam, 1 },
10514     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
10515     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10516     { 0 }
10517 };
10518
10519 static const struct message WmSetWindowRgn_clear[] = {
10520     { WM_WINDOWPOSCHANGING, sent/*|wparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */ },
10521     { WM_NCCALCSIZE, sent|wparam, 1 },
10522     { WM_NCPAINT, sent|optional },
10523     { WM_GETTEXT, sent|defwinproc|optional },
10524     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
10525     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10526     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
10527     { WM_NCPAINT, sent|optional },
10528     { WM_GETTEXT, sent|defwinproc|optional },
10529     { WM_ERASEBKGND, sent|optional },
10530     { WM_WINDOWPOSCHANGING, sent|optional },
10531     { WM_NCCALCSIZE, sent|optional|wparam, 1 },
10532     { WM_NCPAINT, sent|optional },
10533     { WM_GETTEXT, sent|defwinproc|optional },
10534     { WM_ERASEBKGND, sent|optional },
10535     { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10536     { WM_NCCALCSIZE, sent|optional|wparam, 1 },
10537     { WM_NCPAINT, sent|optional },
10538     { WM_GETTEXT, sent|defwinproc|optional },
10539     { WM_ERASEBKGND, sent|optional },
10540     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10541     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10542     { 0 }
10543 };
10544
10545 static void test_SetWindowRgn(void)
10546 {
10547     HRGN hrgn;
10548     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
10549                                 100, 100, 200, 200, 0, 0, 0, NULL);
10550     ok( hwnd != 0, "Failed to create overlapped window\n" );
10551
10552     ShowWindow( hwnd, SW_SHOW );
10553     UpdateWindow( hwnd );
10554     flush_events();
10555     flush_sequence();
10556
10557     trace("testing SetWindowRgn\n");
10558     hrgn = CreateRectRgn( 0, 0, 150, 150 );
10559     SetWindowRgn( hwnd, hrgn, TRUE );
10560     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
10561
10562     hrgn = CreateRectRgn( 30, 30, 160, 160 );
10563     SetWindowRgn( hwnd, hrgn, FALSE );
10564     ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
10565
10566     hrgn = CreateRectRgn( 0, 0, 180, 180 );
10567     SetWindowRgn( hwnd, hrgn, TRUE );
10568     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
10569
10570     SetWindowRgn( hwnd, 0, TRUE );
10571     ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
10572
10573     DestroyWindow( hwnd );
10574 }
10575
10576 /*************************** ShowWindow() test ******************************/
10577 static const struct message WmShowNormal[] = {
10578     { WM_SHOWWINDOW, sent|wparam, 1 },
10579     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10580     { HCBT_ACTIVATE, hook },
10581     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10582     { HCBT_SETFOCUS, hook },
10583     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10584     { 0 }
10585 };
10586 static const struct message WmShow[] = {
10587     { WM_SHOWWINDOW, sent|wparam, 1 },
10588     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10589     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10590     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10591     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10592     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10593     { 0 }
10594 };
10595 static const struct message WmShowNoActivate_1[] = {
10596     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
10597     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10598     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10599     { WM_MOVE, sent|defwinproc|optional },
10600     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10601     { 0 }
10602 };
10603 static const struct message WmShowNoActivate_2[] = {
10604     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
10605     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10606     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10607     { WM_MOVE, sent|defwinproc },
10608     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10609     { HCBT_SETFOCUS, hook|optional },
10610     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
10611     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10612     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10613     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
10614     { 0 }
10615 };
10616 static const struct message WmShowNA_1[] = {
10617     { WM_SHOWWINDOW, sent|wparam, 1 },
10618     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
10619     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10620     { 0 }
10621 };
10622 static const struct message WmShowNA_2[] = {
10623     { WM_SHOWWINDOW, sent|wparam, 1 },
10624     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
10625     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10626     { 0 }
10627 };
10628 static const struct message WmRestore_1[] = {
10629     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
10630     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10631     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10632     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10633     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10634     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10635     { WM_MOVE, sent|defwinproc },
10636     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10637     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
10638     { 0 }
10639 };
10640 static const struct message WmRestore_2[] = {
10641     { WM_SHOWWINDOW, sent|wparam, 1 },
10642     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10643     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10644     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10645     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10646     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10647     { 0 }
10648 };
10649 static const struct message WmRestore_3[] = {
10650     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
10651     { WM_GETMINMAXINFO, sent },
10652     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10653     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
10654     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10655     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
10656     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10657     { WM_MOVE, sent|defwinproc },
10658     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10659     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
10660     { 0 }
10661 };
10662 static const struct message WmRestore_4[] = {
10663     { HCBT_MINMAX, hook|lparam|optional, 0, SW_RESTORE },
10664     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10665     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10666     { WM_MOVE, sent|defwinproc|optional },
10667     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
10668     { 0 }
10669 };
10670 static const struct message WmRestore_5[] = {
10671     { HCBT_MINMAX, hook|lparam|optional, 0, SW_SHOWNORMAL },
10672     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10673     { HCBT_ACTIVATE, hook|optional },
10674     { HCBT_SETFOCUS, hook|optional },
10675     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10676     { WM_MOVE, sent|defwinproc|optional },
10677     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
10678     { 0 }
10679 };
10680 static const struct message WmHide_1[] = {
10681     { WM_SHOWWINDOW, sent|wparam, 0 },
10682     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOACTIVATE },
10683     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOACTIVATE },
10684     { HCBT_ACTIVATE, hook|optional },
10685     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
10686     { 0 }
10687 };
10688 static const struct message WmHide_2[] = {
10689     { WM_SHOWWINDOW, sent|wparam, 0 },
10690     { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
10691     { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
10692     { HCBT_ACTIVATE, hook|optional },
10693     { 0 }
10694 };
10695 static const struct message WmHide_3[] = {
10696     { WM_SHOWWINDOW, sent|wparam, 0 },
10697     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10698     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10699     { HCBT_SETFOCUS, hook|optional },
10700     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10701     { 0 }
10702 };
10703 static const struct message WmShowMinimized_1[] = {
10704     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
10705     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10706     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10707     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10708     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10709     { WM_MOVE, sent|defwinproc },
10710     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
10711     { 0 }
10712 };
10713 static const struct message WmMinimize_1[] = {
10714     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10715     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10716     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10717     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10718     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10719     { WM_MOVE, sent|defwinproc },
10720     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
10721     { 0 }
10722 };
10723 static const struct message WmMinimize_2[] = {
10724     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10725     { HCBT_SETFOCUS, hook|optional },
10726     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10727     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10728     { WM_MOVE, sent|defwinproc },
10729     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
10730     { 0 }
10731 };
10732 static const struct message WmMinimize_3[] = {
10733     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10734     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10735     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10736     { WM_MOVE, sent|defwinproc },
10737     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
10738     { 0 }
10739 };
10740 static const struct message WmShowMinNoActivate[] = {
10741     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
10742     { WM_WINDOWPOSCHANGING, sent },
10743     { WM_WINDOWPOSCHANGED, sent },
10744     { WM_MOVE, sent|defwinproc|optional },
10745     { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
10746     { 0 }
10747 };
10748 static const struct message WmMinMax_1[] = {
10749     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
10750     { 0 }
10751 };
10752 static const struct message WmMinMax_2[] = {
10753     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10754     { WM_GETMINMAXINFO, sent|optional },
10755     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED },
10756     { HCBT_ACTIVATE, hook|optional },
10757     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
10758     { HCBT_SETFOCUS, hook|optional },
10759     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10760     { WM_MOVE, sent|defwinproc|optional },
10761     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MAXIMIZED },
10762     { HCBT_SETFOCUS, hook|optional },
10763     { 0 }
10764 };
10765 static const struct message WmMinMax_3[] = {
10766     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10767     { HCBT_SETFOCUS, hook|optional },
10768     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10769     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10770     { WM_MOVE, sent|defwinproc|optional },
10771     { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
10772     { 0 }
10773 };
10774 static const struct message WmMinMax_4[] = {
10775     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
10776     { 0 }
10777 };
10778 static const struct message WmShowMaximized_1[] = {
10779     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10780     { WM_GETMINMAXINFO, sent },
10781     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10782     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10783     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10784     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10785     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10786     { WM_MOVE, sent|defwinproc },
10787     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10788     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
10789     { 0 }
10790 };
10791 static const struct message WmShowMaximized_2[] = {
10792     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10793     { WM_GETMINMAXINFO, sent },
10794     { WM_WINDOWPOSCHANGING, sent|optional },
10795     { HCBT_ACTIVATE, hook|optional },
10796     { WM_WINDOWPOSCHANGED, sent|optional },
10797     { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
10798     { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
10799     { WM_WINDOWPOSCHANGING, sent|optional },
10800     { HCBT_SETFOCUS, hook|optional },
10801     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10802     { WM_MOVE, sent|defwinproc },
10803     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10804     { HCBT_SETFOCUS, hook|optional },
10805     { 0 }
10806 };
10807 static const struct message WmShowMaximized_3[] = {
10808     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10809     { WM_GETMINMAXINFO, sent|optional },
10810     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10811     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10812     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10813     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10814     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10815     { WM_MOVE, sent|defwinproc|optional },
10816     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10817     { 0 }
10818 };
10819
10820 static void test_ShowWindow(void)
10821 {
10822     /* ShowWindow commands in random order */
10823     static const struct
10824     {
10825         INT cmd; /* ShowWindow command */
10826         LPARAM ret; /* ShowWindow return value */
10827         DWORD style; /* window style after the command */
10828         const struct message *msg; /* message sequence the command produces */
10829         INT wp_cmd, wp_flags; /* window placement after the command */
10830         POINT wp_min, wp_max; /* window placement after the command */
10831         BOOL todo_msg; /* message sequence doesn't match what Wine does */
10832     } sw[] =
10833     {
10834 /*  1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal,
10835            SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
10836 /*  2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq,
10837            SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
10838 /*  3 */ { SW_HIDE, TRUE, 0, WmHide_1,
10839            SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
10840 /*  4 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
10841            SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
10842 /*  5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1,
10843            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10844 /*  6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1,
10845            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10846 /*  7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1,
10847            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10848 /*  8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
10849            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10850 /*  9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1,
10851            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10852 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
10853            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10854 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1,
10855            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10856 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq,
10857            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10858 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1,
10859            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10860 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
10861            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10862 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2,
10863            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10864 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
10865            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10866 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow,
10867            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10868 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
10869            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10870 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
10871            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10872 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
10873            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10874 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
10875            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10876 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate,
10877            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, TRUE },
10878 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4,
10879            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10880 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
10881            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10882 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
10883            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10884 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1,
10885            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10886 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2,
10887            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10888 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
10889            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10890 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
10891            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10892 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1,
10893            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10894 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
10895            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10896 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3,
10897            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10898 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
10899            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10900 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, /* what does this mean?! */
10901            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10902 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq,
10903            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10904 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
10905            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10906 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2,
10907            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10908 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
10909            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10910 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
10911            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10912 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2,
10913            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10914 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
10915            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10916 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2,
10917            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10918 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
10919            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10920 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
10921            SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10922 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
10923            SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10924 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3,
10925            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10926 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4,
10927            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10928 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3,
10929            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10930 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq,
10931            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10932 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
10933            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10934 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
10935            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10936 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1,
10937            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10938 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
10939            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10940 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3,
10941            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10942 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
10943            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10944 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2,
10945            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10946 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
10947            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE }
10948     };
10949     HWND hwnd;
10950     DWORD style;
10951     LPARAM ret;
10952     INT i;
10953     WINDOWPLACEMENT wp;
10954     RECT win_rc, work_rc = {0, 0, 0, 0};
10955
10956 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
10957     hwnd = CreateWindowEx(0, "ShowWindowClass", NULL, WS_BASE,
10958                           120, 120, 90, 90,
10959                           0, 0, 0, NULL);
10960     assert(hwnd);
10961
10962     style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
10963     ok(style == 0, "expected style 0, got %08x\n", style);
10964
10965     flush_events();
10966     flush_sequence();
10967
10968     if (pGetMonitorInfoA && pMonitorFromPoint)
10969     {
10970         HMONITOR hmon;
10971         MONITORINFO mi;
10972         POINT pt = {0, 0};
10973
10974         SetLastError(0xdeadbeef);
10975         hmon = pMonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
10976         ok(hmon != 0, "MonitorFromPoint error %u\n", GetLastError());
10977
10978         mi.cbSize = sizeof(mi);
10979         SetLastError(0xdeadbeef);
10980         ret = pGetMonitorInfoA(hmon, &mi);
10981         ok(ret, "GetMonitorInfo error %u\n", GetLastError());
10982         trace("monitor (%d,%d-%d,%d), work (%d,%d-%d,%d)\n",
10983             mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom,
10984             mi.rcWork.left, mi.rcWork.top, mi.rcWork.right, mi.rcWork.bottom);
10985         work_rc = mi.rcWork;
10986     }
10987
10988     GetWindowRect(hwnd, &win_rc);
10989     OffsetRect(&win_rc, -work_rc.left, -work_rc.top);
10990
10991     wp.length = sizeof(wp);
10992     SetLastError(0xdeadbeaf);
10993     ret = GetWindowPlacement(hwnd, &wp);
10994     ok(ret, "GetWindowPlacement error %u\n", GetLastError());
10995     ok(wp.flags == 0, "expected 0, got %#x\n", wp.flags);
10996     ok(wp.showCmd == SW_SHOWNORMAL, "expected SW_SHOWNORMAL, got %d\n", wp.showCmd);
10997     ok(wp.ptMinPosition.x == -1 && wp.ptMinPosition.y == -1,
10998        "expected -1,-1 got %d,%d\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
10999     ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
11000        "expected -1,-1 got %d,%d\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
11001     if (work_rc.left || work_rc.top) todo_wine /* FIXME: remove once Wine is fixed */
11002     ok(EqualRect(&win_rc, &wp.rcNormalPosition),
11003        "expected %d,%d-%d,%d got %d,%d-%d,%d\n",
11004         win_rc.left, win_rc.top, win_rc.right, win_rc.bottom,
11005         wp.rcNormalPosition.left, wp.rcNormalPosition.top,
11006         wp.rcNormalPosition.right, wp.rcNormalPosition.bottom);
11007     else
11008     ok(EqualRect(&win_rc, &wp.rcNormalPosition),
11009        "expected %d,%d-%d,%d got %d,%d-%d,%d\n",
11010         win_rc.left, win_rc.top, win_rc.right, win_rc.bottom,
11011         wp.rcNormalPosition.left, wp.rcNormalPosition.top,
11012         wp.rcNormalPosition.right, wp.rcNormalPosition.bottom);
11013
11014     for (i = 0; i < sizeof(sw)/sizeof(sw[0]); i++)
11015     {
11016         static const char * const sw_cmd_name[13] =
11017         {
11018             "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
11019             "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
11020             "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
11021             "SW_NORMALNA" /* 0xCC */
11022         };
11023         char comment[64];
11024         INT idx; /* index into the above array of names */
11025
11026         idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
11027
11028         style = GetWindowLong(hwnd, GWL_STYLE);
11029         trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
11030         ret = ShowWindow(hwnd, sw[i].cmd);
11031         ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
11032         style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
11033         ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
11034
11035         sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
11036         ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
11037
11038         wp.length = sizeof(wp);
11039         SetLastError(0xdeadbeaf);
11040         ret = GetWindowPlacement(hwnd, &wp);
11041         ok(ret, "GetWindowPlacement error %u\n", GetLastError());
11042         ok(wp.flags == sw[i].wp_flags, "expected %#x, got %#x\n", sw[i].wp_flags, wp.flags);
11043         ok(wp.showCmd == sw[i].wp_cmd, "expected %d, got %d\n", sw[i].wp_cmd, wp.showCmd);
11044
11045         /* NT moves the minimized window to -32000,-32000, win9x to 3000,3000 */
11046         if ((wp.ptMinPosition.x + work_rc.left == -32000 && wp.ptMinPosition.y + work_rc.top == -32000) ||
11047             (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000))
11048         {
11049             ok((wp.ptMinPosition.x + work_rc.left == sw[i].wp_min.x && wp.ptMinPosition.y + work_rc.top == sw[i].wp_min.y) ||
11050                (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000),
11051                "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
11052         }
11053         else
11054         {
11055             ok(wp.ptMinPosition.x == sw[i].wp_min.x && wp.ptMinPosition.y == sw[i].wp_min.y,
11056                "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
11057         }
11058
11059         if (wp.ptMaxPosition.x != sw[i].wp_max.x || wp.ptMaxPosition.y != sw[i].wp_max.y)
11060         todo_wine
11061         ok(wp.ptMaxPosition.x == sw[i].wp_max.x && wp.ptMaxPosition.y == sw[i].wp_max.y,
11062            "expected %d,%d got %d,%d\n", sw[i].wp_max.x, sw[i].wp_max.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y);
11063         else
11064         ok(wp.ptMaxPosition.x == sw[i].wp_max.x && wp.ptMaxPosition.y == sw[i].wp_max.y,
11065            "expected %d,%d got %d,%d\n", sw[i].wp_max.x, sw[i].wp_max.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y);
11066
11067 if (0) /* FIXME: Wine behaves completely different here */
11068         ok(EqualRect(&win_rc, &wp.rcNormalPosition),
11069            "expected %d,%d-%d,%d got %d,%d-%d,%d\n",
11070             win_rc.left, win_rc.top, win_rc.right, win_rc.bottom,
11071             wp.rcNormalPosition.left, wp.rcNormalPosition.top,
11072             wp.rcNormalPosition.right, wp.rcNormalPosition.bottom);
11073
11074         flush_events();
11075         flush_sequence();
11076     }
11077
11078     DestroyWindow(hwnd);
11079 }
11080
11081 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11082 {
11083     struct recvd_message msg;
11084
11085     if (ignore_message( message )) return 0;
11086
11087     msg.hwnd = hwnd;
11088     msg.message = message;
11089     msg.flags = sent|wparam|lparam;
11090     msg.wParam = wParam;
11091     msg.lParam = lParam;
11092     msg.descr = "dialog";
11093     add_message(&msg);
11094
11095     /* calling DefDlgProc leads to a recursion under XP */
11096
11097     switch (message)
11098     {
11099     case WM_INITDIALOG:
11100     case WM_GETDLGCODE:
11101         return 0;
11102     }
11103     return 1;
11104 }
11105
11106 static const struct message WmDefDlgSetFocus_1[] = {
11107     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
11108     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
11109     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
11110     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
11111     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
11112     { HCBT_SETFOCUS, hook },
11113     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11114     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11115     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11116     { WM_SETFOCUS, sent|wparam, 0 },
11117     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11118     { WM_CTLCOLOREDIT, sent },
11119     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11120     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11121     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11122     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11123     { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
11124     { 0 }
11125 };
11126 static const struct message WmDefDlgSetFocus_2[] = {
11127     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
11128     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
11129     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
11130     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
11131     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
11132     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11133     { WM_CTLCOLOREDIT, sent|optional }, /* XP */
11134     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11135     { 0 }
11136 };
11137 /* Creation of a dialog */
11138 static const struct message WmCreateDialogParamSeq_1[] = {
11139     { HCBT_CREATEWND, hook },
11140     { WM_NCCREATE, sent },
11141     { WM_NCCALCSIZE, sent|wparam, 0 },
11142     { WM_CREATE, sent },
11143     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
11144     { WM_SIZE, sent|wparam, SIZE_RESTORED },
11145     { WM_MOVE, sent },
11146     { WM_SETFONT, sent },
11147     { WM_INITDIALOG, sent },
11148     { WM_CHANGEUISTATE, sent|optional },
11149     { 0 }
11150 };
11151 /* Creation of a dialog */
11152 static const struct message WmCreateDialogParamSeq_2[] = {
11153     { HCBT_CREATEWND, hook },
11154     { WM_NCCREATE, sent },
11155     { WM_NCCALCSIZE, sent|wparam, 0 },
11156     { WM_CREATE, sent },
11157     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
11158     { WM_SIZE, sent|wparam, SIZE_RESTORED },
11159     { WM_MOVE, sent },
11160     { WM_CHANGEUISTATE, sent|optional },
11161     { 0 }
11162 };
11163
11164 static void test_dialog_messages(void)
11165 {
11166     WNDCLASS cls;
11167     HWND hdlg, hedit1, hedit2, hfocus;
11168     LRESULT ret;
11169
11170 #define set_selection(hctl, start, end) \
11171     ret = SendMessage(hctl, EM_SETSEL, start, end); \
11172     ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
11173
11174 #define check_selection(hctl, start, end) \
11175     ret = SendMessage(hctl, EM_GETSEL, 0, 0); \
11176     ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
11177
11178     subclass_edit();
11179
11180     hdlg = CreateWindowEx(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
11181                           WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
11182                           0, 0, 100, 100, 0, 0, 0, NULL);
11183     ok(hdlg != 0, "Failed to create custom dialog window\n");
11184
11185     hedit1 = CreateWindowEx(0, "my_edit_class", NULL,
11186                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
11187                            0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
11188     ok(hedit1 != 0, "Failed to create edit control\n");
11189     hedit2 = CreateWindowEx(0, "my_edit_class", NULL,
11190                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
11191                            0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
11192     ok(hedit2 != 0, "Failed to create edit control\n");
11193
11194     SendMessage(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
11195     SendMessage(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
11196
11197     hfocus = GetFocus();
11198     ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
11199
11200     SetFocus(hedit2);
11201     hfocus = GetFocus();
11202     ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
11203
11204     check_selection(hedit1, 0, 0);
11205     check_selection(hedit2, 0, 0);
11206
11207     set_selection(hedit2, 0, -1);
11208     check_selection(hedit2, 0, 3);
11209
11210     SetFocus(0);
11211     hfocus = GetFocus();
11212     ok(hfocus == 0, "wrong focus %p\n", hfocus);
11213
11214     flush_sequence();
11215     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
11216     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
11217     ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
11218
11219     hfocus = GetFocus();
11220     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
11221
11222     check_selection(hedit1, 0, 5);
11223     check_selection(hedit2, 0, 3);
11224
11225     flush_sequence();
11226     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
11227     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
11228     ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
11229
11230     hfocus = GetFocus();
11231     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
11232
11233     check_selection(hedit1, 0, 5);
11234     check_selection(hedit2, 0, 3);
11235
11236     EndDialog(hdlg, 0);
11237     DestroyWindow(hedit1);
11238     DestroyWindow(hedit2);
11239     DestroyWindow(hdlg);
11240     flush_sequence();
11241
11242 #undef set_selection
11243 #undef check_selection
11244
11245     ok(GetClassInfo(0, "#32770", &cls), "GetClassInfo failed\n");
11246     cls.lpszClassName = "MyDialogClass";
11247     cls.hInstance = GetModuleHandle(0);
11248     /* need a cast since a dlgproc is used as a wndproc */
11249     cls.lpfnWndProc = test_dlg_proc;
11250     if (!RegisterClass(&cls)) assert(0);
11251
11252     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
11253     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
11254     ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
11255     EndDialog(hdlg, 0);
11256     DestroyWindow(hdlg);
11257     flush_sequence();
11258
11259     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
11260     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
11261     ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
11262     EndDialog(hdlg, 0);
11263     DestroyWindow(hdlg);
11264     flush_sequence();
11265
11266     UnregisterClass(cls.lpszClassName, cls.hInstance);
11267 }
11268
11269 static void test_EndDialog(void)
11270 {
11271     HWND hparent, hother, hactive, hdlg;
11272     WNDCLASS cls;
11273
11274     hparent = CreateWindowExA(0, "TestParentClass", "Test parent",
11275                               WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_DISABLED,
11276                               100, 100, 200, 200, 0, 0, 0, NULL);
11277     ok (hparent != 0, "Failed to create parent window\n");
11278
11279     hother = CreateWindowExA(0, "TestParentClass", "Test parent 2",
11280                               WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11281                               100, 100, 200, 200, 0, 0, 0, NULL);
11282     ok (hother != 0, "Failed to create parent window\n");
11283
11284     ok(GetClassInfo(0, "#32770", &cls), "GetClassInfo failed\n");
11285     cls.lpszClassName = "MyDialogClass";
11286     cls.hInstance = GetModuleHandle(0);
11287     cls.lpfnWndProc = test_dlg_proc;
11288     if (!RegisterClass(&cls)) assert(0);
11289
11290     flush_sequence();
11291     SetForegroundWindow(hother);
11292     hactive = GetForegroundWindow();
11293     ok(hother == hactive, "Wrong window has focus (%p != %p)\n", hother, hactive);
11294
11295     /* create a dialog where the parent is disabled, this parent should still
11296        receive the focus when the dialog exits (even though "normally" a
11297        disabled window should not receive the focus) */
11298     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", hparent, test_dlg_proc, 0);
11299     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
11300     SetForegroundWindow(hdlg);
11301     hactive = GetForegroundWindow();
11302     ok(hdlg == hactive, "Wrong window has focus (%p != %p)\n", hdlg, hactive);
11303     EndDialog(hdlg, 0);
11304     hactive = GetForegroundWindow();
11305     ok(hparent == hactive, "Wrong window has focus (parent != active) (active: %p, parent: %p, dlg: %p, other: %p)\n", hactive, hparent, hdlg, hother);
11306     DestroyWindow(hdlg);
11307     flush_sequence();
11308
11309     DestroyWindow( hother );
11310     DestroyWindow( hparent );
11311     UnregisterClass(cls.lpszClassName, cls.hInstance);
11312 }
11313
11314 static void test_nullCallback(void)
11315 {
11316     HWND hwnd;
11317
11318     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
11319                            100, 100, 200, 200, 0, 0, 0, NULL);
11320     ok (hwnd != 0, "Failed to create overlapped window\n");
11321
11322     SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
11323     flush_events();
11324     DestroyWindow(hwnd);
11325 }
11326
11327 /* SetActiveWindow( 0 ) hwnd visible */
11328 static const struct message SetActiveWindowSeq0[] =
11329 {
11330     { HCBT_ACTIVATE, hook|optional },
11331     { WM_NCACTIVATE, sent|wparam, 0 },
11332     { WM_GETTEXT, sent|defwinproc|optional },
11333     { WM_ACTIVATE, sent|wparam, 0 },
11334     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
11335     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
11336     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11337     { WM_KILLFOCUS, sent|optional },
11338     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
11339     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
11340     { WM_NCACTIVATE, sent|wparam|optional, 1 },
11341     { WM_GETTEXT, sent|defwinproc|optional },
11342     { WM_ACTIVATE, sent|wparam|optional, 1 },
11343     { HCBT_SETFOCUS, hook|optional },
11344     { WM_KILLFOCUS, sent|defwinproc|optional },
11345     { WM_IME_SETCONTEXT, sent|defwinproc|optional },
11346     { WM_IME_SETCONTEXT, sent|defwinproc|optional },
11347     { WM_IME_SETCONTEXT, sent|optional },
11348     { WM_IME_SETCONTEXT, sent|optional },
11349     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
11350     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11351     { WM_SETFOCUS, sent|defwinproc|optional },
11352     { WM_GETTEXT, sent|optional },
11353     { 0 }
11354 };
11355 /* SetActiveWindow( hwnd ) hwnd visible */
11356 static const struct message SetActiveWindowSeq1[] =
11357 {
11358     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11359     { 0 }
11360 };
11361 /* SetActiveWindow( popup ) hwnd visible, popup visible */
11362 static const struct message SetActiveWindowSeq2[] =
11363 {
11364     { HCBT_ACTIVATE, hook },
11365     { WM_NCACTIVATE, sent|wparam, 0 },
11366     { WM_GETTEXT, sent|defwinproc|optional },
11367     { WM_ACTIVATE, sent|wparam, 0 },
11368     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11369     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
11370     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
11371     { WM_NCPAINT, sent|optional },
11372     { WM_GETTEXT, sent|defwinproc|optional },
11373     { WM_ERASEBKGND, sent|optional },
11374     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11375     { WM_NCACTIVATE, sent|wparam, 1 },
11376     { WM_GETTEXT, sent|defwinproc|optional },
11377     { WM_ACTIVATE, sent|wparam, 1 },
11378     { HCBT_SETFOCUS, hook },
11379     { WM_KILLFOCUS, sent|defwinproc },
11380     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
11381     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11382     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
11383     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11384     { WM_SETFOCUS, sent|defwinproc },
11385     { WM_GETTEXT, sent|optional },
11386     { 0 }
11387 };
11388
11389 /* SetActiveWindow( hwnd ) hwnd not visible */
11390 static const struct message SetActiveWindowSeq3[] =
11391 {
11392     { HCBT_ACTIVATE, hook },
11393     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11394     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
11395     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
11396     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11397     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11398     { WM_ACTIVATEAPP, sent|wparam, 1 },
11399     { WM_ACTIVATEAPP, sent|wparam, 1 },
11400     { WM_NCACTIVATE, sent|wparam, 1 },
11401     { WM_ACTIVATE, sent|wparam, 1 },
11402     { HCBT_SETFOCUS, hook },
11403     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11404     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11405     { WM_SETFOCUS, sent|defwinproc },
11406     { 0 }
11407 };
11408 /* SetActiveWindow( popup ) hwnd not visible, popup not visible */
11409 static const struct message SetActiveWindowSeq4[] =
11410 {
11411     { HCBT_ACTIVATE, hook },
11412     { WM_NCACTIVATE, sent|wparam, 0 },
11413     { WM_GETTEXT, sent|defwinproc|optional },
11414     { WM_ACTIVATE, sent|wparam, 0 },
11415     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11416     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
11417     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
11418     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11419     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11420     { WM_NCACTIVATE, sent|wparam, 1 },
11421     { WM_GETTEXT, sent|defwinproc|optional },
11422     { WM_ACTIVATE, sent|wparam, 1 },
11423     { HCBT_SETFOCUS, hook },
11424     { WM_KILLFOCUS, sent|defwinproc },
11425     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
11426     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11427     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
11428     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11429     { WM_SETFOCUS, sent|defwinproc },
11430     { 0 }
11431 };
11432
11433
11434 static void test_SetActiveWindow(void)
11435 {
11436     HWND hwnd, popup, ret;
11437
11438     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
11439                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11440                            100, 100, 200, 200, 0, 0, 0, NULL);
11441
11442     popup = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
11443                            WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_POPUP,
11444                            100, 100, 200, 200, hwnd, 0, 0, NULL);
11445
11446     ok(hwnd != 0, "Failed to create overlapped window\n");
11447     ok(popup != 0, "Failed to create popup window\n");
11448     SetForegroundWindow( popup );
11449     flush_sequence();
11450
11451     trace("SetActiveWindow(0)\n");
11452     ret = SetActiveWindow(0);
11453     ok( ret == popup, "Failed to SetActiveWindow(0)\n");
11454     ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", FALSE);
11455     flush_sequence();
11456
11457     trace("SetActiveWindow(hwnd), hwnd visible\n");
11458     ret = SetActiveWindow(hwnd);
11459     if (ret == hwnd) ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE);
11460     flush_sequence();
11461
11462     trace("SetActiveWindow(popup), hwnd visible, popup visible\n");
11463     ret = SetActiveWindow(popup);
11464     ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n");
11465     ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visible", FALSE);
11466     flush_sequence();
11467
11468     ShowWindow(hwnd, SW_HIDE);
11469     ShowWindow(popup, SW_HIDE);
11470     flush_sequence();
11471
11472     trace("SetActiveWindow(hwnd), hwnd not visible\n");
11473     ret = SetActiveWindow(hwnd);
11474     ok( ret == NULL, "SetActiveWindow(hwnd), hwnd not visible, previous is %p\n", ret );
11475     ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE);
11476     flush_sequence();
11477
11478     trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n");
11479     ret = SetActiveWindow(popup);
11480     ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n");
11481     ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visible", TRUE);
11482     flush_sequence();
11483
11484     trace("done\n");
11485
11486     DestroyWindow(hwnd);
11487 }
11488
11489 static const struct message SetForegroundWindowSeq[] =
11490 {
11491     { WM_NCACTIVATE, sent|wparam, 0 },
11492     { WM_GETTEXT, sent|defwinproc|optional },
11493     { WM_ACTIVATE, sent|wparam, 0 },
11494     { WM_ACTIVATEAPP, sent|wparam, 0 },
11495     { WM_KILLFOCUS, sent },
11496     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
11497     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
11498     { 0 }
11499 };
11500
11501 static void test_SetForegroundWindow(void)
11502 {
11503     HWND hwnd;
11504
11505     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
11506                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11507                            100, 100, 200, 200, 0, 0, 0, NULL);
11508     ok (hwnd != 0, "Failed to create overlapped window\n");
11509     SetForegroundWindow( hwnd );
11510     flush_sequence();
11511
11512     trace("SetForegroundWindow( 0 )\n");
11513     SetForegroundWindow( 0 );
11514     ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
11515     trace("SetForegroundWindow( GetDesktopWindow() )\n");
11516     SetForegroundWindow( GetDesktopWindow() );
11517     ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
11518                                         "foreground top level window", FALSE);
11519     trace("done\n");
11520
11521     DestroyWindow(hwnd);
11522 }
11523
11524 static void test_dbcs_wm_char(void)
11525 {
11526     BYTE dbch[2];
11527     WCHAR wch, bad_wch;
11528     HWND hwnd, hwnd2;
11529     MSG msg;
11530     DWORD time;
11531     POINT pt;
11532     DWORD_PTR res;
11533     CPINFOEXA cpinfo;
11534     UINT i, j, k;
11535     struct message wmCharSeq[2];
11536     BOOL ret;
11537
11538     if (!pGetCPInfoExA)
11539     {
11540         win_skip("GetCPInfoExA is not available\n");
11541         return;
11542     }
11543
11544     pGetCPInfoExA( CP_ACP, 0, &cpinfo );
11545     if (cpinfo.MaxCharSize != 2)
11546     {
11547         skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
11548         return;
11549     }
11550
11551     dbch[0] = dbch[1] = 0;
11552     wch = 0;
11553     bad_wch = cpinfo.UnicodeDefaultChar;
11554     for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
11555         for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
11556             for (k = 128; k <= 255; k++)
11557             {
11558                 char str[2];
11559                 WCHAR wstr[2];
11560                 str[0] = j;
11561                 str[1] = k;
11562                 if (MultiByteToWideChar( CP_ACP, 0, str, 2, wstr, 2 ) == 1 &&
11563                     WideCharToMultiByte( CP_ACP, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
11564                     (BYTE)str[0] == j && (BYTE)str[1] == k &&
11565                     HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
11566                 {
11567                     dbch[0] = j;
11568                     dbch[1] = k;
11569                     wch = wstr[0];
11570                     break;
11571                 }
11572             }
11573
11574     if (!wch)
11575     {
11576         skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
11577         return;
11578     }
11579     trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
11580            dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
11581
11582     hwnd = CreateWindowExW(0, testWindowClassW, NULL,
11583                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
11584     hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
11585                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
11586     ok (hwnd != 0, "Failed to create overlapped window\n");
11587     ok (hwnd2 != 0, "Failed to create overlapped window\n");
11588     flush_sequence();
11589
11590     memset( wmCharSeq, 0, sizeof(wmCharSeq) );
11591     wmCharSeq[0].message = WM_CHAR;
11592     wmCharSeq[0].flags = sent|wparam;
11593     wmCharSeq[0].wParam = wch;
11594
11595     /* posted message */
11596     PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11597     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11598     ok( !ret, "got message %x\n", msg.message );
11599     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11600     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11601     ok( ret, "no message\n" );
11602     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11603     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
11604     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11605     ok( !ret, "got message %x\n", msg.message );
11606
11607     /* posted thread message */
11608     PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
11609     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11610     ok( !ret, "got message %x\n", msg.message );
11611     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11612     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11613     ok( ret, "no message\n" );
11614     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11615     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
11616     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11617     ok( !ret, "got message %x\n", msg.message );
11618
11619     /* sent message */
11620     flush_sequence();
11621     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11622     ok_sequence( WmEmptySeq, "no messages", FALSE );
11623     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11624     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11625     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11626     ok( !ret, "got message %x\n", msg.message );
11627
11628     /* sent message with timeout */
11629     flush_sequence();
11630     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
11631     ok_sequence( WmEmptySeq, "no messages", FALSE );
11632     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
11633     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11634     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11635     ok( !ret, "got message %x\n", msg.message );
11636
11637     /* sent message with timeout and callback */
11638     flush_sequence();
11639     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
11640     ok_sequence( WmEmptySeq, "no messages", FALSE );
11641     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
11642     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11643     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11644     ok( !ret, "got message %x\n", msg.message );
11645
11646     /* sent message with callback */
11647     flush_sequence();
11648     SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11649     ok_sequence( WmEmptySeq, "no messages", FALSE );
11650     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
11651     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11652     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11653     ok( !ret, "got message %x\n", msg.message );
11654
11655     /* direct window proc call */
11656     flush_sequence();
11657     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
11658     ok_sequence( WmEmptySeq, "no messages", FALSE );
11659     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
11660     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11661
11662     /* dispatch message */
11663     msg.hwnd = hwnd;
11664     msg.message = WM_CHAR;
11665     msg.wParam = dbch[0];
11666     msg.lParam = 0;
11667     DispatchMessageA( &msg );
11668     ok_sequence( WmEmptySeq, "no messages", FALSE );
11669     msg.wParam = dbch[1];
11670     DispatchMessageA( &msg );
11671     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11672
11673     /* window handle is irrelevant */
11674     flush_sequence();
11675     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
11676     ok_sequence( WmEmptySeq, "no messages", FALSE );
11677     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11678     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11679     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11680     ok( !ret, "got message %x\n", msg.message );
11681
11682     /* interleaved post and send */
11683     flush_sequence();
11684     PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
11685     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
11686     ok_sequence( WmEmptySeq, "no messages", FALSE );
11687     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11688     ok( !ret, "got message %x\n", msg.message );
11689     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11690     ok_sequence( WmEmptySeq, "no messages", FALSE );
11691     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11692     ok( ret, "no message\n" );
11693     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11694     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
11695     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11696     ok( !ret, "got message %x\n", msg.message );
11697     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11698     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11699     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11700     ok( !ret, "got message %x\n", msg.message );
11701
11702     /* interleaved sent message and winproc */
11703     flush_sequence();
11704     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11705     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
11706     ok_sequence( WmEmptySeq, "no messages", FALSE );
11707     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11708     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11709     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
11710     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11711
11712     /* interleaved winproc and dispatch */
11713     msg.hwnd = hwnd;
11714     msg.message = WM_CHAR;
11715     msg.wParam = dbch[0];
11716     msg.lParam = 0;
11717     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
11718     DispatchMessageA( &msg );
11719     ok_sequence( WmEmptySeq, "no messages", FALSE );
11720     msg.wParam = dbch[1];
11721     DispatchMessageA( &msg );
11722     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11723     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
11724     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11725
11726     /* interleaved sends */
11727     flush_sequence();
11728     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11729     SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
11730     ok_sequence( WmEmptySeq, "no messages", FALSE );
11731     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
11732     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11733     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11734     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11735
11736     /* dbcs WM_CHAR */
11737     flush_sequence();
11738     SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
11739     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11740     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11741     ok( !ret, "got message %x\n", msg.message );
11742
11743     /* other char messages are not magic */
11744     PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
11745     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11746     ok( ret, "no message\n" );
11747     ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
11748     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
11749     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11750     ok( !ret, "got message %x\n", msg.message );
11751     PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
11752     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11753     ok( ret, "no message\n" );
11754     ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
11755     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
11756     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11757     ok( !ret, "got message %x\n", msg.message );
11758
11759     /* test retrieving messages */
11760
11761     PostMessageW( hwnd, WM_CHAR, wch, 0 );
11762     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
11763     ok( ret, "no message\n" );
11764     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11765     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11766     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11767     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
11768     ok( ret, "no message\n" );
11769     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11770     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11771     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11772     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
11773     ok( !ret, "got message %x\n", msg.message );
11774
11775     /* message filters */
11776     PostMessageW( hwnd, WM_CHAR, wch, 0 );
11777     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
11778     ok( ret, "no message\n" );
11779     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11780     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11781     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11782     /* message id is filtered, hwnd is not */
11783     ret = PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE );
11784     ok( !ret, "no message\n" );
11785     ret = PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE );
11786     ok( ret, "no message\n" );
11787     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11788     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11789     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11790     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
11791     ok( !ret, "got message %x\n", msg.message );
11792
11793     /* mixing GetMessage and PostMessage */
11794     PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
11795     ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
11796     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11797     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11798     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11799     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
11800     time = msg.time;
11801     pt = msg.pt;
11802     ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time );
11803     ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
11804     ok( ret, "no message\n" );
11805     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11806     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11807     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11808     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
11809     ok( msg.time == time, "bad time %x/%x\n", msg.time, time );
11810     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 );
11811     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
11812     ok( !ret, "got message %x\n", msg.message );
11813
11814     /* without PM_REMOVE */
11815     PostMessageW( hwnd, WM_CHAR, wch, 0 );
11816     ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
11817     ok( ret, "no message\n" );
11818     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11819     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11820     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11821     ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
11822     ok( ret, "no message\n" );
11823     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11824     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11825     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11826     ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
11827     ok( ret, "no message\n" );
11828     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11829     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11830     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11831     ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
11832     ok( ret, "no message\n" );
11833     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11834     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11835     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11836     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
11837     ok( !ret, "got message %x\n", msg.message );
11838
11839     DestroyWindow(hwnd);
11840     DestroyWindow(hwnd2);
11841 }
11842
11843 #define ID_LISTBOX 0x000f
11844
11845 static const struct message wm_lb_setcursel_0[] =
11846 {
11847     { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
11848     { WM_CTLCOLORLISTBOX, sent|parent },
11849     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
11850     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11851     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11852     { 0 }
11853 };
11854 static const struct message wm_lb_setcursel_1[] =
11855 {
11856     { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
11857     { WM_CTLCOLORLISTBOX, sent|parent },
11858     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
11859     { WM_CTLCOLORLISTBOX, sent|parent },
11860     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
11861     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
11862     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
11863     { 0 }
11864 };
11865 static const struct message wm_lb_setcursel_2[] =
11866 {
11867     { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
11868     { WM_CTLCOLORLISTBOX, sent|parent },
11869     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
11870     { WM_CTLCOLORLISTBOX, sent|parent },
11871     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
11872     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
11873     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
11874     { 0 }
11875 };
11876 static const struct message wm_lb_click_0[] =
11877 {
11878     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
11879     { HCBT_SETFOCUS, hook },
11880     { WM_KILLFOCUS, sent|parent },
11881     { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
11882     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11883     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11884     { WM_SETFOCUS, sent|defwinproc },
11885
11886     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
11887     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
11888     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
11889     { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
11890     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11891
11892     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
11893     { WM_CTLCOLORLISTBOX, sent|parent },
11894     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
11895     { WM_CTLCOLORLISTBOX, sent|parent },
11896     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
11897     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
11898
11899     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11900     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11901
11902     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
11903     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
11904     { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
11905     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
11906     { 0 }
11907 };
11908 static const struct message wm_lb_deletestring[] =
11909 {
11910     { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
11911     { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
11912     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11913     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11914     { 0 }
11915 };
11916 static const struct message wm_lb_deletestring_reset[] =
11917 {
11918     { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
11919     { LB_RESETCONTENT, sent|wparam|lparam|defwinproc|optional, 0, 0 },
11920     { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
11921     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11922     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11923     { 0 }
11924 };
11925
11926 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
11927
11928 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
11929
11930 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
11931 {
11932     static LONG defwndproc_counter = 0;
11933     LRESULT ret;
11934     struct recvd_message msg;
11935
11936     /* do not log painting messages */
11937     if (message != WM_PAINT &&
11938         message != WM_NCPAINT &&
11939         message != WM_SYNCPAINT &&
11940         message != WM_ERASEBKGND &&
11941         message != WM_NCHITTEST &&
11942         message != WM_GETTEXT &&
11943         !ignore_message( message ))
11944     {
11945         msg.hwnd = hwnd;
11946         msg.message = message;
11947         msg.flags = sent|wparam|lparam;
11948         if (defwndproc_counter) msg.flags |= defwinproc;
11949         msg.wParam = wp;
11950         msg.lParam = lp;
11951         msg.descr = "listbox";
11952         add_message(&msg);
11953     }
11954
11955     defwndproc_counter++;
11956     ret = CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
11957     defwndproc_counter--;
11958
11959     return ret;
11960 }
11961
11962 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
11963                                int caret_index, int top_index, int line)
11964 {
11965     LRESULT ret;
11966
11967     /* calling an orig proc helps to avoid unnecessary message logging */
11968     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
11969     ok_(__FILE__, line)(ret == count, "expected count %d, got %ld\n", count, ret);
11970     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
11971     ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret);
11972     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
11973     ok_(__FILE__, line)(ret == caret_index ||
11974                         broken(cur_sel == -1 && caret_index == 0 && ret == -1),  /* nt4 */
11975                         "expected caret index %d, got %ld\n", caret_index, ret);
11976     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
11977     ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret);
11978 }
11979
11980 static void test_listbox_messages(void)
11981 {
11982     HWND parent, listbox;
11983     LRESULT ret;
11984
11985     parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW  | WS_VISIBLE,
11986                              100, 100, 200, 200, 0, 0, 0, NULL);
11987     listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
11988                               WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
11989                               10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
11990     listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
11991
11992     check_lb_state(listbox, 0, LB_ERR, 0, 0);
11993
11994     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
11995     ok(ret == 0, "expected 0, got %ld\n", ret);
11996     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
11997     ok(ret == 1, "expected 1, got %ld\n", ret);
11998     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
11999     ok(ret == 2, "expected 2, got %ld\n", ret);
12000
12001     check_lb_state(listbox, 3, LB_ERR, 0, 0);
12002
12003     flush_sequence();
12004
12005     log_all_parent_messages++;
12006
12007     trace("selecting item 0\n");
12008     ret = SendMessage(listbox, LB_SETCURSEL, 0, 0);
12009     ok(ret == 0, "expected 0, got %ld\n", ret);
12010     ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
12011     check_lb_state(listbox, 3, 0, 0, 0);
12012     flush_sequence();
12013
12014     trace("selecting item 1\n");
12015     ret = SendMessage(listbox, LB_SETCURSEL, 1, 0);
12016     ok(ret == 1, "expected 1, got %ld\n", ret);
12017     ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
12018     check_lb_state(listbox, 3, 1, 1, 0);
12019
12020     trace("selecting item 2\n");
12021     ret = SendMessage(listbox, LB_SETCURSEL, 2, 0);
12022     ok(ret == 2, "expected 2, got %ld\n", ret);
12023     ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
12024     check_lb_state(listbox, 3, 2, 2, 0);
12025
12026     trace("clicking on item 0\n");
12027     ret = SendMessage(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
12028     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
12029     ret = SendMessage(listbox, WM_LBUTTONUP, 0, 0);
12030     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
12031     ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
12032     check_lb_state(listbox, 3, 0, 0, 0);
12033     flush_sequence();
12034
12035     trace("deleting item 0\n");
12036     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
12037     ok(ret == 2, "expected 2, got %ld\n", ret);
12038     ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
12039     check_lb_state(listbox, 2, -1, 0, 0);
12040     flush_sequence();
12041
12042     trace("deleting item 0\n");
12043     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
12044     ok(ret == 1, "expected 1, got %ld\n", ret);
12045     ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
12046     check_lb_state(listbox, 1, -1, 0, 0);
12047     flush_sequence();
12048
12049     trace("deleting item 0\n");
12050     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
12051     ok(ret == 0, "expected 0, got %ld\n", ret);
12052     ok_sequence(wm_lb_deletestring_reset, "LB_DELETESTRING 0", FALSE );
12053     check_lb_state(listbox, 0, -1, 0, 0);
12054     flush_sequence();
12055
12056     trace("deleting item 0\n");
12057     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
12058     ok(ret == LB_ERR, "expected LB_ERR, got %ld\n", ret);
12059     check_lb_state(listbox, 0, -1, 0, 0);
12060     flush_sequence();
12061
12062     log_all_parent_messages--;
12063
12064     DestroyWindow(listbox);
12065     DestroyWindow(parent);
12066 }
12067
12068 /*************************** Menu test ******************************/
12069 static const struct message wm_popup_menu_1[] =
12070 {
12071     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
12072     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
12073     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0x20000001 },
12074     { WM_SYSKEYDOWN, sent|wparam|lparam, 'E', 0x20000001 },
12075     { WM_SYSCHAR, sent|wparam|lparam, 'e', 0x20000001 },
12076     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'e' },
12077     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
12078     { WM_INITMENU, sent|lparam, 0, 0 },
12079     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) },
12080     { WM_INITMENUPOPUP, sent|lparam, 0, 1 },
12081     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */
12082     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) },
12083     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 },
12084     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
12085     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001, 0, 0x40000000 },
12086     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */
12087     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
12088     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
12089     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
12090     { WM_MENUCOMMAND, sent }, /* |wparam, 200 - Win9x */
12091     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
12092     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
12093     { 0 }
12094 };
12095 static const struct message wm_popup_menu_2[] =
12096 {
12097     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
12098     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
12099     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
12100     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
12101     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
12102     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
12103     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
12104     { WM_INITMENU, sent|lparam, 0, 0 },
12105     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
12106     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
12107     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
12108     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
12109     { HCBT_CREATEWND, hook },
12110     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
12111                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
12112     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
12113     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
12114     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
12115     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
12116     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
12117     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
12118     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
12119     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
12120     { HCBT_DESTROYWND, hook },
12121     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
12122     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
12123     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
12124     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
12125     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
12126     { WM_MENUCOMMAND, sent }, /* |wparam, 100 - Win9x */
12127     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
12128     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
12129     { 0 }
12130 };
12131 static const struct message wm_popup_menu_3[] =
12132 {
12133     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
12134     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
12135     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
12136     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
12137     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
12138     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
12139     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
12140     { WM_INITMENU, sent|lparam, 0, 0 },
12141     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
12142     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
12143     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
12144     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
12145     { HCBT_CREATEWND, hook },
12146     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
12147                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
12148     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
12149     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
12150     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
12151     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
12152     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
12153     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
12154     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
12155     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
12156     { HCBT_DESTROYWND, hook },
12157     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
12158     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
12159     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
12160     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
12161     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
12162     { WM_COMMAND, sent|wparam|lparam, 100, 0 },
12163     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
12164     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
12165     { 0 }
12166 };
12167
12168 static const struct message wm_single_menu_item[] =
12169 {
12170     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
12171     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
12172     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0x20000001 },
12173     { WM_SYSKEYDOWN, sent|wparam|lparam, 'Q', 0x20000001 },
12174     { WM_SYSCHAR, sent|wparam|lparam, 'q', 0x20000001 },
12175     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'q' },
12176     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
12177     { WM_INITMENU, sent|lparam, 0, 0 },
12178     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(300,MF_HILITE) },
12179     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
12180     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
12181     { WM_MENUCOMMAND, sent },
12182     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0xe0000001 },
12183     { WM_SYSKEYUP, sent|wparam|lparam, 'Q', 0xe0000001 },
12184     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 },
12185     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
12186
12187     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 1 },
12188     { WM_KEYDOWN, sent|wparam|lparam, VK_ESCAPE, 1 },
12189     { WM_CHAR,  sent|wparam|lparam, VK_ESCAPE, 0x00000001 },
12190     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 },
12191     { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
12192     { 0 }
12193 };
12194
12195 static LRESULT WINAPI parent_menu_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
12196 {
12197     if (message == WM_ENTERIDLE ||
12198         message == WM_INITMENU ||
12199         message == WM_INITMENUPOPUP ||
12200         message == WM_MENUSELECT ||
12201         message == WM_PARENTNOTIFY ||
12202         message == WM_ENTERMENULOOP ||
12203         message == WM_EXITMENULOOP ||
12204         message == WM_UNINITMENUPOPUP ||
12205         message == WM_KEYDOWN ||
12206         message == WM_KEYUP ||
12207         message == WM_CHAR ||
12208         message == WM_SYSKEYDOWN ||
12209         message == WM_SYSKEYUP ||
12210         message == WM_SYSCHAR ||
12211         message == WM_COMMAND ||
12212         message == WM_MENUCOMMAND)
12213     {
12214         struct recvd_message msg;
12215
12216         msg.hwnd = hwnd;
12217         msg.message = message;
12218         msg.flags = sent|wparam|lparam;
12219         msg.wParam = wp;
12220         msg.lParam = lp;
12221         msg.descr = "parent_menu_proc";
12222         add_message(&msg);
12223     }
12224
12225     return DefWindowProcA(hwnd, message, wp, lp);
12226 }
12227
12228 static void set_menu_style(HMENU hmenu, DWORD style)
12229 {
12230     MENUINFO mi;
12231     BOOL ret;
12232
12233     mi.cbSize = sizeof(mi);
12234     mi.fMask = MIM_STYLE;
12235     mi.dwStyle = style;
12236     SetLastError(0xdeadbeef);
12237     ret = pSetMenuInfo(hmenu, &mi);
12238     ok(ret, "SetMenuInfo error %u\n", GetLastError());
12239 }
12240
12241 static DWORD get_menu_style(HMENU hmenu)
12242 {
12243     MENUINFO mi;
12244     BOOL ret;
12245
12246     mi.cbSize = sizeof(mi);
12247     mi.fMask = MIM_STYLE;
12248     mi.dwStyle = 0;
12249     SetLastError(0xdeadbeef);
12250     ret = pGetMenuInfo(hmenu, &mi);
12251     ok(ret, "GetMenuInfo error %u\n", GetLastError());
12252
12253     return mi.dwStyle;
12254 }
12255
12256 static void test_menu_messages(void)
12257 {
12258     MSG msg;
12259     WNDCLASSA cls;
12260     HMENU hmenu, hmenu_popup;
12261     HWND hwnd;
12262     DWORD style;
12263
12264     if (!pGetMenuInfo || !pSetMenuInfo)
12265     {
12266         win_skip("GetMenuInfo and/or SetMenuInfo are not available\n");
12267         return;
12268     }
12269     cls.style = 0;
12270     cls.lpfnWndProc = parent_menu_proc;
12271     cls.cbClsExtra = 0;
12272     cls.cbWndExtra = 0;
12273     cls.hInstance = GetModuleHandleA(0);
12274     cls.hIcon = 0;
12275     cls.hCursor = LoadCursorA(0, IDC_ARROW);
12276     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
12277     cls.lpszMenuName = NULL;
12278     cls.lpszClassName = "TestMenuClass";
12279     UnregisterClass(cls.lpszClassName, cls.hInstance);
12280     if (!RegisterClassA(&cls)) assert(0);
12281
12282     SetLastError(0xdeadbeef);
12283     hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
12284                            100, 100, 200, 200, 0, 0, 0, NULL);
12285     ok(hwnd != 0, "LoadMenuA error %u\n", GetLastError());
12286
12287     SetLastError(0xdeadbeef);
12288     hmenu = LoadMenuA(GetModuleHandle(0), MAKEINTRESOURCE(1));
12289     ok(hmenu != 0, "LoadMenuA error %u\n", GetLastError());
12290
12291     SetMenu(hwnd, hmenu);
12292     SetForegroundWindow( hwnd );
12293
12294     set_menu_style(hmenu, MNS_NOTIFYBYPOS);
12295     style = get_menu_style(hmenu);
12296     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
12297
12298     hmenu_popup = GetSubMenu(hmenu, 0);
12299     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
12300     style = get_menu_style(hmenu_popup);
12301     ok(style == 0, "expected 0, got %u\n", style);
12302
12303     hmenu_popup = GetSubMenu(hmenu_popup, 0);
12304     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
12305     style = get_menu_style(hmenu_popup);
12306     ok(style == 0, "expected 0, got %u\n", style);
12307
12308     /* Alt+E, Enter */
12309     trace("testing a popup menu command\n");
12310     flush_sequence();
12311     keybd_event(VK_MENU, 0, 0, 0);
12312     keybd_event('E', 0, 0, 0);
12313     keybd_event('E', 0, KEYEVENTF_KEYUP, 0);
12314     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
12315     keybd_event(VK_RETURN, 0, 0, 0);
12316     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
12317     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
12318     {
12319         TranslateMessage(&msg);
12320         DispatchMessage(&msg);
12321     }
12322     if (!sequence_cnt)  /* we didn't get any message */
12323     {
12324         skip( "queuing key events not supported\n" );
12325         goto done;
12326     }
12327     /* win98 queues only a WM_KEYUP and doesn't start menu tracking */
12328     if (sequence[0].message == WM_KEYUP && sequence[0].wParam == VK_MENU)
12329     {
12330         win_skip( "menu tracking through VK_MENU not supported\n" );
12331         goto done;
12332     }
12333     ok_sequence(wm_popup_menu_1, "popup menu command", FALSE);
12334
12335     /* Alt+F, Right, Enter */
12336     trace("testing submenu of a popup menu command\n");
12337     flush_sequence();
12338     keybd_event(VK_MENU, 0, 0, 0);
12339     keybd_event('F', 0, 0, 0);
12340     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
12341     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
12342     keybd_event(VK_RIGHT, 0, 0, 0);
12343     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
12344     keybd_event(VK_RETURN, 0, 0, 0);
12345     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
12346     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
12347     {
12348         TranslateMessage(&msg);
12349         DispatchMessage(&msg);
12350     }
12351     ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE);
12352
12353     trace("testing single menu item command\n");
12354     flush_sequence();
12355     keybd_event(VK_MENU, 0, 0, 0);
12356     keybd_event('Q', 0, 0, 0);
12357     keybd_event('Q', 0, KEYEVENTF_KEYUP, 0);
12358     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
12359     keybd_event(VK_ESCAPE, 0, 0, 0);
12360     keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
12361     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
12362     {
12363         TranslateMessage(&msg);
12364         DispatchMessage(&msg);
12365     }
12366     ok_sequence(wm_single_menu_item, "single menu item command", FALSE);
12367
12368     set_menu_style(hmenu, 0);
12369     style = get_menu_style(hmenu);
12370     ok(style == 0, "expected 0, got %u\n", style);
12371
12372     hmenu_popup = GetSubMenu(hmenu, 0);
12373     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
12374     set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS);
12375     style = get_menu_style(hmenu_popup);
12376     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
12377
12378     hmenu_popup = GetSubMenu(hmenu_popup, 0);
12379     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
12380     style = get_menu_style(hmenu_popup);
12381     ok(style == 0, "expected 0, got %u\n", style);
12382
12383     /* Alt+F, Right, Enter */
12384     trace("testing submenu of a popup menu command\n");
12385     flush_sequence();
12386     keybd_event(VK_MENU, 0, 0, 0);
12387     keybd_event('F', 0, 0, 0);
12388     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
12389     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
12390     keybd_event(VK_RIGHT, 0, 0, 0);
12391     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
12392     keybd_event(VK_RETURN, 0, 0, 0);
12393     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
12394     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
12395     {
12396         TranslateMessage(&msg);
12397         DispatchMessage(&msg);
12398     }
12399     ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE);
12400
12401 done:
12402     DestroyWindow(hwnd);
12403     DestroyMenu(hmenu);
12404 }
12405
12406
12407 static void test_paintingloop(void)
12408 {
12409     HWND hwnd;
12410
12411     paint_loop_done = 0;
12412     hwnd = CreateWindowExA(0x0,"PaintLoopWindowClass",
12413                                "PaintLoopWindowClass",WS_OVERLAPPEDWINDOW,
12414                                 100, 100, 100, 100, 0, 0, 0, NULL );
12415     ok(hwnd != 0, "PaintLoop window error %u\n", GetLastError());
12416     ShowWindow(hwnd,SW_NORMAL);
12417     SetFocus(hwnd);
12418
12419     while (!paint_loop_done)
12420     {
12421         MSG msg;
12422         if (PeekMessageA(&msg, 0, 0, 0, 1))
12423         {
12424             TranslateMessage(&msg);
12425             DispatchMessage(&msg);
12426         }
12427     }
12428     DestroyWindow(hwnd);
12429 }
12430
12431 static void test_defwinproc(void)
12432 {
12433     HWND hwnd;
12434     MSG msg;
12435     int gotwmquit = FALSE;
12436     hwnd = CreateWindowExA(0, "static", "test_defwndproc", WS_POPUP, 0,0,0,0,0,0,0, NULL);
12437     assert(hwnd);
12438     DefWindowProcA( hwnd, WM_ENDSESSION, 1, 0);
12439     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) {
12440         if( msg.message == WM_QUIT) gotwmquit = TRUE;
12441         DispatchMessageA( &msg );
12442     }
12443     ok( gotwmquit == FALSE, "Unexpected WM_QUIT message!\n");
12444     DestroyWindow( hwnd);
12445 }
12446
12447 #define clear_clipboard(hwnd)  clear_clipboard_(__LINE__, (hwnd))
12448 static void clear_clipboard_(int line, HWND hWnd)
12449 {
12450     BOOL succ;
12451     succ = OpenClipboard(hWnd);
12452     ok_(__FILE__, line)(succ, "OpenClipboard failed, err=%u\n", GetLastError());
12453     succ = EmptyClipboard();
12454     ok_(__FILE__, line)(succ, "EmptyClipboard failed, err=%u\n", GetLastError());
12455     succ = CloseClipboard();
12456     ok_(__FILE__, line)(succ, "CloseClipboard failed, err=%u\n", GetLastError());
12457 }
12458
12459 #define expect_HWND(expected, got) expect_HWND_(__LINE__, (expected), (got))
12460 static void expect_HWND_(int line, HWND expected, HWND got)
12461 {
12462     ok_(__FILE__, line)(got==expected, "Expected %p, got %p\n", expected, got);
12463 }
12464
12465 static WNDPROC pOldViewerProc;
12466
12467 static LRESULT CALLBACK recursive_viewer_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
12468 {
12469     static BOOL recursion_guard;
12470
12471     if (message == WM_DRAWCLIPBOARD && !recursion_guard)
12472     {
12473         recursion_guard = TRUE;
12474         clear_clipboard(hWnd);
12475         recursion_guard = FALSE;
12476     }
12477     return CallWindowProcA(pOldViewerProc, hWnd, message, wParam, lParam);
12478 }
12479
12480 static void test_clipboard_viewers(void)
12481 {
12482     static struct message wm_change_cb_chain[] =
12483     {
12484         { WM_CHANGECBCHAIN, sent|wparam|lparam, 0, 0 },
12485         { 0 }
12486     };
12487     static const struct message wm_clipboard_destroyed[] =
12488     {
12489         { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
12490         { 0 }
12491     };
12492     static struct message wm_clipboard_changed[] =
12493     {
12494         { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
12495         { 0 }
12496     };
12497     static struct message wm_clipboard_changed_and_owned[] =
12498     {
12499         { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
12500         { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
12501         { 0 }
12502     };
12503
12504     HINSTANCE hInst = GetModuleHandleA(NULL);
12505     HWND hWnd1, hWnd2, hWnd3;
12506     HWND hOrigViewer;
12507     HWND hRet;
12508
12509     hWnd1 = CreateWindowExA(0, "TestWindowClass", "Clipboard viewer test wnd 1",
12510         WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
12511         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
12512         GetDesktopWindow(), NULL, hInst, NULL);
12513     hWnd2 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 2",
12514         WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
12515         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
12516         GetDesktopWindow(), NULL, hInst, NULL);
12517     hWnd3 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 3",
12518         WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
12519         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
12520         GetDesktopWindow(), NULL, hInst, NULL);
12521     trace("clipbd viewers: hWnd1=%p, hWnd2=%p, hWnd3=%p\n", hWnd1, hWnd2, hWnd3);
12522     assert(hWnd1 && hWnd2 && hWnd3);
12523
12524     flush_sequence();
12525
12526     /* Test getting the clipboard viewer and setting the viewer to NULL. */
12527     hOrigViewer = GetClipboardViewer();
12528     hRet = SetClipboardViewer(NULL);
12529     ok_sequence(WmEmptySeq, "set viewer to NULL", FALSE);
12530     expect_HWND(hOrigViewer, hRet);
12531     expect_HWND(NULL, GetClipboardViewer());
12532
12533     /* Test registering hWnd1 as a viewer. */
12534     hRet = SetClipboardViewer(hWnd1);
12535     wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
12536     ok_sequence(wm_clipboard_changed, "set viewer NULL->1", FALSE);
12537     expect_HWND(NULL, hRet);
12538     expect_HWND(hWnd1, GetClipboardViewer());
12539
12540     /* Test that changing the clipboard actually refreshes the registered viewer. */
12541     clear_clipboard(hWnd1);
12542     wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
12543     ok_sequence(wm_clipboard_changed, "clear clipbd (viewer=owner=1)", FALSE);
12544
12545     /* Again, but with different owner. */
12546     clear_clipboard(hWnd2);
12547     wm_clipboard_changed_and_owned[1].wParam = (WPARAM) GetClipboardOwner();
12548     ok_sequence(wm_clipboard_changed_and_owned, "clear clipbd (viewer=1, owner=2)", FALSE);
12549
12550     /* Test re-registering same window. */
12551     hRet = SetClipboardViewer(hWnd1);
12552     wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
12553     ok_sequence(wm_clipboard_changed, "set viewer 1->1", FALSE);
12554     expect_HWND(hWnd1, hRet);
12555     expect_HWND(hWnd1, GetClipboardViewer());
12556
12557     /* Test ChangeClipboardChain. */
12558     ChangeClipboardChain(hWnd2, hWnd3);
12559     wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
12560     wm_change_cb_chain[0].lParam = (LPARAM) hWnd3;
12561     ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=3)", FALSE);
12562     expect_HWND(hWnd1, GetClipboardViewer());
12563
12564     ChangeClipboardChain(hWnd2, NULL);
12565     wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
12566     wm_change_cb_chain[0].lParam = 0;
12567     ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=NULL)", FALSE);
12568     expect_HWND(hWnd1, GetClipboardViewer());
12569
12570     ChangeClipboardChain(NULL, hWnd2);
12571     ok_sequence(WmEmptySeq, "change chain (viewer=1, remove=NULL, next=2)", TRUE);
12572     expect_HWND(hWnd1, GetClipboardViewer());
12573
12574     /* Actually change clipboard viewer with ChangeClipboardChain. */
12575     ChangeClipboardChain(hWnd1, hWnd2);
12576     ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=2)", FALSE);
12577     expect_HWND(hWnd2, GetClipboardViewer());
12578
12579     /* Test that no refresh messages are sent when viewer has unregistered. */
12580     clear_clipboard(hWnd2);
12581     ok_sequence(WmEmptySeq, "clear clipd (viewer=2, owner=1)", FALSE);
12582
12583     /* Register hWnd1 again. */
12584     ChangeClipboardChain(hWnd2, hWnd1);
12585     ok_sequence(WmEmptySeq, "change chain (viewer=remove=2, next=1)", FALSE);
12586     expect_HWND(hWnd1, GetClipboardViewer());
12587
12588     /* Subclass hWnd1 so that when it receives a WM_DRAWCLIPBOARD message, it
12589      * changes the clipboard. When this happens, the system shouldn't send
12590      * another WM_DRAWCLIPBOARD (as this could cause an infinite loop).
12591      */
12592     pOldViewerProc = (WNDPROC) SetWindowLongPtrA(hWnd1, GWLP_WNDPROC, (LONG_PTR) recursive_viewer_proc);
12593     clear_clipboard(hWnd2);
12594     /* The clipboard owner is changed in recursive_viewer_proc: */
12595     wm_clipboard_changed[0].wParam = (WPARAM) hWnd2;
12596     ok_sequence(wm_clipboard_changed, "recursive clear clipbd (viewer=1, owner=2)", TRUE);
12597
12598     /* Test unregistering. */
12599     ChangeClipboardChain(hWnd1, NULL);
12600     ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=NULL)", FALSE);
12601     expect_HWND(NULL, GetClipboardViewer());
12602
12603     clear_clipboard(hWnd1);
12604     ok_sequence(wm_clipboard_destroyed, "clear clipbd (no viewer, owner=1)", FALSE);
12605
12606     DestroyWindow(hWnd1);
12607     DestroyWindow(hWnd2);
12608     DestroyWindow(hWnd3);
12609     SetClipboardViewer(hOrigViewer);
12610 }
12611
12612 static void test_PostMessage(void)
12613 {
12614     static const struct
12615     {
12616         HWND hwnd;
12617         BOOL ret;
12618     } data[] =
12619     {
12620         { HWND_TOP /* 0 */, TRUE },
12621         { HWND_BROADCAST, TRUE },
12622         { HWND_BOTTOM, TRUE },
12623         { HWND_TOPMOST, TRUE },
12624         { HWND_NOTOPMOST, FALSE },
12625         { HWND_MESSAGE, FALSE },
12626         { (HWND)0xdeadbeef, FALSE }
12627     };
12628     int i;
12629     HWND hwnd;
12630     BOOL ret;
12631     MSG msg;
12632     static const WCHAR staticW[] = {'s','t','a','t','i','c',0};
12633
12634     SetLastError(0xdeadbeef);
12635     hwnd = CreateWindowExW(0, staticW, NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
12636     if (!hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
12637     {
12638         win_skip("Skipping some PostMessage tests on Win9x/WinMe\n");
12639         return;
12640     }
12641     assert(hwnd);
12642
12643     flush_events();
12644
12645     PostMessage(hwnd, WM_USER+1, 0x1234, 0x5678);
12646     PostMessage(0, WM_USER+2, 0x5678, 0x1234);
12647
12648     for (i = 0; i < sizeof(data)/sizeof(data[0]); i++)
12649     {
12650         memset(&msg, 0xab, sizeof(msg));
12651         ret = PeekMessageA(&msg, data[i].hwnd, 0, 0, PM_NOREMOVE);
12652         ok(ret == data[i].ret, "%d: hwnd %p expected %d, got %d\n", i, data[i].hwnd, data[i].ret, ret);
12653         if (data[i].ret)
12654         {
12655             if (data[i].hwnd)
12656                 ok(ret && msg.hwnd == 0 && msg.message == WM_USER+2 &&
12657                    msg.wParam == 0x5678 && msg.lParam == 0x1234,
12658                    "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/0/WM_USER+2/0x5678/0x1234\n",
12659                    i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam);
12660             else
12661                 ok(ret && msg.hwnd == hwnd && msg.message == WM_USER+1 &&
12662                    msg.wParam == 0x1234 && msg.lParam == 0x5678,
12663                    "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/%p/WM_USER+1/0x1234/0x5678\n",
12664                    i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam, msg.hwnd);
12665         }
12666     }
12667
12668     DestroyWindow(hwnd);
12669     flush_events();
12670 }
12671
12672 static const struct
12673 {
12674     DWORD exp, broken;
12675     BOOL todo;
12676 } wait_idle_expect[] =
12677 {
12678 /* 0 */  { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
12679          { WAIT_TIMEOUT, 0,            FALSE },
12680          { WAIT_TIMEOUT, 0,            FALSE },
12681          { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
12682          { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
12683 /* 5 */  { WAIT_TIMEOUT, 0,            FALSE },
12684          { WAIT_TIMEOUT, 0,            FALSE },
12685          { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
12686          { 0,            0,            FALSE },
12687          { 0,            0,            FALSE },
12688 /* 10 */ { 0,            0,            FALSE },
12689          { 0,            0,            FALSE },
12690          { 0,            WAIT_TIMEOUT, FALSE },
12691          { 0,            0,            FALSE },
12692          { 0,            0,            FALSE },
12693 /* 15 */ { 0,            0,            FALSE },
12694          { WAIT_TIMEOUT, 0,            FALSE },
12695          { WAIT_TIMEOUT, 0,            FALSE },
12696          { WAIT_TIMEOUT, 0,            FALSE },
12697          { WAIT_TIMEOUT, 0,            FALSE },
12698 /* 20 */ { WAIT_TIMEOUT, 0,            FALSE },
12699 };
12700
12701 static DWORD CALLBACK do_wait_idle_child_thread( void *arg )
12702 {
12703     MSG msg;
12704
12705     PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE );
12706     Sleep( 200 );
12707     MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
12708     return 0;
12709 }
12710
12711 static void do_wait_idle_child( int arg )
12712 {
12713     WNDCLASS cls;
12714     MSG msg;
12715     HWND hwnd = 0;
12716     HANDLE thread;
12717     DWORD id;
12718     HANDLE start_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_start" );
12719     HANDLE end_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_end" );
12720
12721     memset( &cls, 0, sizeof(cls) );
12722     cls.lpfnWndProc   = DefWindowProc;
12723     cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
12724     cls.hCursor       = LoadCursor(0, IDC_ARROW);
12725     cls.lpszClassName = "TestClass";
12726     RegisterClass( &cls );
12727
12728     PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE );  /* create the msg queue */
12729
12730     ok( start_event != 0, "failed to create start event, error %u\n", GetLastError() );
12731     ok( end_event != 0, "failed to create end event, error %u\n", GetLastError() );
12732
12733     switch (arg)
12734     {
12735     case 0:
12736         SetEvent( start_event );
12737         break;
12738     case 1:
12739         SetEvent( start_event );
12740         Sleep( 200 );
12741         PeekMessage( &msg, 0, 0, 0, PM_REMOVE );
12742         break;
12743     case 2:
12744         SetEvent( start_event );
12745         Sleep( 200 );
12746         PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE );
12747         PostThreadMessage( GetCurrentThreadId(), WM_COMMAND, 0x1234, 0xabcd );
12748         PeekMessage( &msg, 0, 0, 0, PM_REMOVE );
12749         break;
12750     case 3:
12751         SetEvent( start_event );
12752         Sleep( 200 );
12753         SendMessage( HWND_BROADCAST, WM_WININICHANGE, 0, 0 );
12754         break;
12755     case 4:
12756         SetEvent( start_event );
12757         Sleep( 200 );
12758         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
12759         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessage( &msg );
12760         break;
12761     case 5:
12762         SetEvent( start_event );
12763         Sleep( 200 );
12764         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
12765         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
12766         break;
12767     case 6:
12768         SetEvent( start_event );
12769         Sleep( 200 );
12770         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
12771         while (PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE ))
12772         {
12773             GetMessage( &msg, 0, 0, 0 );
12774             DispatchMessage( &msg );
12775         }
12776         break;
12777     case 7:
12778         SetEvent( start_event );
12779         Sleep( 200 );
12780         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
12781         SetTimer( hwnd, 3, 1, NULL );
12782         Sleep( 200 );
12783         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessage( &msg );
12784         break;
12785     case 8:
12786         SetEvent( start_event );
12787         Sleep( 200 );
12788         PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE );
12789         MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
12790         break;
12791     case 9:
12792         SetEvent( start_event );
12793         Sleep( 200 );
12794         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
12795         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
12796         for (;;) GetMessage( &msg, 0, 0, 0 );
12797         break;
12798     case 10:
12799         SetEvent( start_event );
12800         Sleep( 200 );
12801         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
12802         SetTimer( hwnd, 3, 1, NULL );
12803         Sleep( 200 );
12804         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
12805         break;
12806     case 11:
12807         SetEvent( start_event );
12808         Sleep( 200 );
12809         return;  /* exiting the process makes WaitForInputIdle return success too */
12810     case 12:
12811         PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE );
12812         Sleep( 200 );
12813         MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
12814         SetEvent( start_event );
12815         break;
12816     case 13:
12817         SetEvent( start_event );
12818         PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE );
12819         Sleep( 200 );
12820         thread = CreateThread( NULL, 0, do_wait_idle_child_thread, NULL, 0, &id );
12821         WaitForSingleObject( thread, 10000 );
12822         CloseHandle( thread );
12823         break;
12824     case 14:
12825         SetEvent( start_event );
12826         Sleep( 200 );
12827         PeekMessage( &msg, HWND_TOPMOST, 0, 0, PM_NOREMOVE );
12828         break;
12829     case 15:
12830         SetEvent( start_event );
12831         Sleep( 200 );
12832         PeekMessage( &msg, HWND_BROADCAST, 0, 0, PM_NOREMOVE );
12833         break;
12834     case 16:
12835         SetEvent( start_event );
12836         Sleep( 200 );
12837         PeekMessage( &msg, HWND_BOTTOM, 0, 0, PM_NOREMOVE );
12838         break;
12839     case 17:
12840         SetEvent( start_event );
12841         Sleep( 200 );
12842         PeekMessage( &msg, (HWND)0xdeadbeef, 0, 0, PM_NOREMOVE );
12843         break;
12844     case 18:
12845         SetEvent( start_event );
12846         Sleep( 200 );
12847         PeekMessage( &msg, HWND_NOTOPMOST, 0, 0, PM_NOREMOVE );
12848         break;
12849     case 19:
12850         SetEvent( start_event );
12851         Sleep( 200 );
12852         PeekMessage( &msg, HWND_MESSAGE, 0, 0, PM_NOREMOVE );
12853         break;
12854     case 20:
12855         SetEvent( start_event );
12856         Sleep( 200 );
12857         PeekMessage( &msg, GetDesktopWindow(), 0, 0, PM_NOREMOVE );
12858         break;
12859     }
12860     WaitForSingleObject( end_event, 2000 );
12861     CloseHandle( start_event );
12862     CloseHandle( end_event );
12863     if (hwnd) DestroyWindow( hwnd );
12864 }
12865
12866 static LRESULT CALLBACK wait_idle_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
12867 {
12868     if (msg == WM_WININICHANGE) Sleep( 200 );  /* make sure the child waits */
12869     return DefWindowProcA( hwnd, msg, wp, lp );
12870 }
12871
12872 static DWORD CALLBACK wait_idle_thread( void *arg )
12873 {
12874     WNDCLASS cls;
12875     MSG msg;
12876     HWND hwnd;
12877
12878     memset( &cls, 0, sizeof(cls) );
12879     cls.lpfnWndProc   = wait_idle_proc;
12880     cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
12881     cls.hCursor       = LoadCursor(0, IDC_ARROW);
12882     cls.lpszClassName = "TestClass";
12883     RegisterClass( &cls );
12884
12885     hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL);
12886     while (GetMessage( &msg, 0, 0, 0 )) DispatchMessage( &msg );
12887     DestroyWindow(hwnd);
12888     return 0;
12889 }
12890
12891 static void test_WaitForInputIdle( char *argv0 )
12892 {
12893     char path[MAX_PATH];
12894     PROCESS_INFORMATION pi;
12895     STARTUPINFOA startup;
12896     BOOL ret;
12897     HANDLE start_event, end_event, thread;
12898     unsigned int i;
12899     DWORD id;
12900     const IMAGE_DOS_HEADER *dos = (const IMAGE_DOS_HEADER *)GetModuleHandleA(0);
12901     const IMAGE_NT_HEADERS *nt = (const IMAGE_NT_HEADERS *)((const char *)dos + dos->e_lfanew);
12902     BOOL console_app = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_GUI);
12903
12904     if (console_app)  /* build the test with -mwindows for better coverage */
12905         trace( "not built as a GUI app, WaitForInputIdle may not be fully tested\n" );
12906
12907     start_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_start");
12908     end_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_end");
12909     ok(start_event != 0, "failed to create start event, error %u\n", GetLastError());
12910     ok(end_event != 0, "failed to create end event, error %u\n", GetLastError());
12911
12912     memset( &startup, 0, sizeof(startup) );
12913     startup.cb = sizeof(startup);
12914     startup.dwFlags = STARTF_USESHOWWINDOW;
12915     startup.wShowWindow = SW_SHOWNORMAL;
12916
12917     thread = CreateThread( NULL, 0, wait_idle_thread, NULL, 0, &id );
12918
12919     for (i = 0; i < sizeof(wait_idle_expect)/sizeof(wait_idle_expect[0]); i++)
12920     {
12921         ResetEvent( start_event );
12922         ResetEvent( end_event );
12923         sprintf( path, "%s msg %u", argv0, i );
12924         ret = CreateProcessA( NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &pi );
12925         ok( ret, "CreateProcess '%s' failed err %u.\n", path, GetLastError() );
12926         if (ret)
12927         {
12928             ret = WaitForSingleObject( start_event, 5000 );
12929             ok( ret == WAIT_OBJECT_0, "%u: WaitForSingleObject failed\n", i );
12930             if (ret == WAIT_OBJECT_0)
12931             {
12932                 ret = WaitForInputIdle( pi.hProcess, 1000 );
12933                 if (ret == WAIT_FAILED)
12934                     ok( console_app ||
12935                         ret == wait_idle_expect[i].exp ||
12936                         broken(ret == wait_idle_expect[i].broken),
12937                         "%u: WaitForInputIdle error %08x expected %08x\n",
12938                         i, ret, wait_idle_expect[i].exp );
12939                 else if (wait_idle_expect[i].todo)
12940                     todo_wine
12941                     ok( ret == wait_idle_expect[i].exp || broken(ret == wait_idle_expect[i].broken),
12942                         "%u: WaitForInputIdle error %08x expected %08x\n",
12943                         i, ret, wait_idle_expect[i].exp );
12944                 else
12945                     ok( ret == wait_idle_expect[i].exp || broken(ret == wait_idle_expect[i].broken),
12946                         "%u: WaitForInputIdle error %08x expected %08x\n",
12947                         i, ret, wait_idle_expect[i].exp );
12948                 SetEvent( end_event );
12949                 WaitForSingleObject( pi.hProcess, 1000 );  /* give it a chance to exit on its own */
12950             }
12951             TerminateProcess( pi.hProcess, 0 );  /* just in case */
12952             winetest_wait_child_process( pi.hProcess );
12953             ret = WaitForInputIdle( pi.hProcess, 100 );
12954             ok( ret == WAIT_FAILED, "%u: WaitForInputIdle after exit error %08x\n", i, ret );
12955             CloseHandle( pi.hProcess );
12956             CloseHandle( pi.hThread );
12957         }
12958     }
12959     CloseHandle( start_event );
12960     PostThreadMessage( id, WM_QUIT, 0, 0 );
12961     WaitForSingleObject( thread, 10000 );
12962     CloseHandle( thread );
12963 }
12964
12965 static const struct message WmSetParentSeq_1[] = {
12966     { WM_SHOWWINDOW, sent|wparam, 0 },
12967     { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12968     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
12969     { WM_CHILDACTIVATE, sent },
12970     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE },
12971     { WM_MOVE, sent|defwinproc|wparam, 0 },
12972     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12973     { WM_SHOWWINDOW, sent|wparam, 1 },
12974     { 0 }
12975 };
12976
12977 static const struct message WmSetParentSeq_2[] = {
12978     { WM_SHOWWINDOW, sent|wparam, 0 },
12979     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
12980     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
12981     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12982     { HCBT_SETFOCUS, hook|optional },
12983     { WM_NCACTIVATE, sent|wparam|optional, 0 },
12984     { WM_ACTIVATE, sent|wparam|optional, 0 },
12985     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
12986     { WM_KILLFOCUS, sent|wparam, 0 },
12987     { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12988     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
12989     { HCBT_ACTIVATE, hook|optional },
12990     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
12991     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
12992     { WM_NCACTIVATE, sent|wparam|optional, 1 },
12993     { WM_ACTIVATE, sent|wparam|optional, 1 },
12994     { HCBT_SETFOCUS, hook|optional },
12995     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
12996     { WM_SETFOCUS, sent|optional|defwinproc },
12997     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOCLIENTSIZE },
12998     { WM_MOVE, sent|defwinproc|wparam, 0 },
12999     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
13000     { WM_SHOWWINDOW, sent|wparam, 1 },
13001     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
13002     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
13003     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13004     { 0 }
13005 };
13006
13007
13008 static void test_SetParent(void)
13009 {
13010     HWND parent1, parent2, child, popup;
13011     RECT rc, rc_old;
13012
13013     parent1 = CreateWindowEx(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
13014                             100, 100, 200, 200, 0, 0, 0, NULL);
13015     ok(parent1 != 0, "Failed to create parent1 window\n");
13016
13017     parent2 = CreateWindowEx(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
13018                             400, 100, 200, 200, 0, 0, 0, NULL);
13019     ok(parent2 != 0, "Failed to create parent2 window\n");
13020
13021     /* WS_CHILD window */
13022     child = CreateWindowEx(0, "TestWindowClass", NULL, WS_CHILD | WS_VISIBLE,
13023                            10, 10, 150, 150, parent1, 0, 0, NULL);
13024     ok(child != 0, "Failed to create child window\n");
13025
13026     GetWindowRect(parent1, &rc);
13027     trace("parent1 (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
13028     GetWindowRect(child, &rc_old);
13029     MapWindowPoints(0, parent1, (POINT *)&rc_old, 2);
13030     trace("child (%d,%d)-(%d,%d)\n", rc_old.left, rc_old.top, rc_old.right, rc_old.bottom);
13031
13032     flush_sequence();
13033
13034     SetParent(child, parent2);
13035     flush_events();
13036     ok_sequence(WmSetParentSeq_1, "SetParent() visible WS_CHILD", TRUE);
13037
13038     ok(GetWindowLongA(child, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
13039     ok(!IsWindowVisible(child), "IsWindowVisible() should return FALSE\n");
13040
13041     GetWindowRect(parent2, &rc);
13042     trace("parent2 (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
13043     GetWindowRect(child, &rc);
13044     MapWindowPoints(0, parent2, (POINT *)&rc, 2);
13045     trace("child (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
13046
13047     ok(EqualRect(&rc_old, &rc), "rects do not match (%d,%d-%d,%d) / (%d,%d-%d,%d)\n",
13048        rc_old.left, rc_old.top, rc_old.right, rc_old.bottom,
13049        rc.left, rc.top, rc.right, rc.bottom );
13050
13051     /* WS_POPUP window */
13052     popup = CreateWindowEx(0, "TestWindowClass", NULL, WS_POPUP | WS_VISIBLE,
13053                            20, 20, 100, 100, 0, 0, 0, NULL);
13054     ok(popup != 0, "Failed to create popup window\n");
13055
13056     GetWindowRect(popup, &rc_old);
13057     trace("popup (%d,%d)-(%d,%d)\n", rc_old.left, rc_old.top, rc_old.right, rc_old.bottom);
13058
13059     flush_sequence();
13060
13061     SetParent(popup, child);
13062     flush_events();
13063     ok_sequence(WmSetParentSeq_2, "SetParent() visible WS_POPUP", TRUE);
13064
13065     ok(GetWindowLongA(popup, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
13066     ok(!IsWindowVisible(popup), "IsWindowVisible() should return FALSE\n");
13067
13068     GetWindowRect(child, &rc);
13069     trace("parent2 (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
13070     GetWindowRect(popup, &rc);
13071     MapWindowPoints(0, child, (POINT *)&rc, 2);
13072     trace("popup (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
13073
13074     ok(EqualRect(&rc_old, &rc), "rects do not match (%d,%d-%d,%d) / (%d,%d-%d,%d)\n",
13075        rc_old.left, rc_old.top, rc_old.right, rc_old.bottom,
13076        rc.left, rc.top, rc.right, rc.bottom );
13077
13078     DestroyWindow(popup);
13079     DestroyWindow(child);
13080     DestroyWindow(parent1);
13081     DestroyWindow(parent2);
13082
13083     flush_sequence();
13084 }
13085
13086 static const struct message WmKeyReleaseOnly[] = {
13087     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x80000001 },
13088     { WM_KEYUP, sent|wparam|lparam, 0x41, 0x80000001 },
13089     { 0 }
13090 };
13091 static const struct message WmKeyPressNormal[] = {
13092     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x1 },
13093     { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x1 },
13094     { 0 }
13095 };
13096 static const struct message WmKeyPressRepeat[] = {
13097     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x40000001 },
13098     { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x40000001 },
13099     { 0 }
13100 };
13101 static const struct message WmKeyReleaseNormal[] = {
13102     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0xc0000001 },
13103     { WM_KEYUP, sent|wparam|lparam, 0x41, 0xc0000001 },
13104     { 0 }
13105 };
13106
13107 static void test_keyflags(void)
13108 {
13109     HWND test_window;
13110     SHORT key_state;
13111     BYTE keyboard_state[256];
13112     MSG msg;
13113
13114     test_window = CreateWindowEx(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13115                            100, 100, 200, 200, 0, 0, 0, NULL);
13116
13117     flush_events();
13118     flush_sequence();
13119
13120     /* keyup without a keydown */
13121     keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
13122     while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13123         DispatchMessage(&msg);
13124     ok_sequence(WmKeyReleaseOnly, "key release only", TRUE);
13125
13126     key_state = GetAsyncKeyState(0x41);
13127     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13128
13129     key_state = GetKeyState(0x41);
13130     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13131
13132     /* keydown */
13133     keybd_event(0x41, 0, 0, 0);
13134     while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13135         DispatchMessage(&msg);
13136     ok_sequence(WmKeyPressNormal, "key press only", FALSE);
13137
13138     key_state = GetAsyncKeyState(0x41);
13139     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13140
13141     key_state = GetKeyState(0x41);
13142     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13143
13144     /* keydown repeat */
13145     keybd_event(0x41, 0, 0, 0);
13146     while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13147         DispatchMessage(&msg);
13148     ok_sequence(WmKeyPressRepeat, "key press repeat", FALSE);
13149
13150     key_state = GetAsyncKeyState(0x41);
13151     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13152
13153     key_state = GetKeyState(0x41);
13154     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13155
13156     /* keyup */
13157     keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
13158     while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13159         DispatchMessage(&msg);
13160     ok_sequence(WmKeyReleaseNormal, "key release repeat", FALSE);
13161
13162     key_state = GetAsyncKeyState(0x41);
13163     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13164
13165     key_state = GetKeyState(0x41);
13166     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13167
13168     /* set the key state in this thread */
13169     GetKeyboardState(keyboard_state);
13170     keyboard_state[0x41] = 0x80;
13171     SetKeyboardState(keyboard_state);
13172
13173     key_state = GetAsyncKeyState(0x41);
13174     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13175
13176     /* keydown */
13177     keybd_event(0x41, 0, 0, 0);
13178     while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13179         DispatchMessage(&msg);
13180     ok_sequence(WmKeyPressRepeat, "key press after setkeyboardstate", TRUE);
13181
13182     key_state = GetAsyncKeyState(0x41);
13183     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13184
13185     key_state = GetKeyState(0x41);
13186     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13187
13188     /* clear the key state in this thread */
13189     GetKeyboardState(keyboard_state);
13190     keyboard_state[0x41] = 0;
13191     SetKeyboardState(keyboard_state);
13192
13193     key_state = GetAsyncKeyState(0x41);
13194     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13195
13196     /* keyup */
13197     keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
13198     while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13199         DispatchMessage(&msg);
13200     ok_sequence(WmKeyReleaseOnly, "key release after setkeyboardstate", TRUE);
13201
13202     key_state = GetAsyncKeyState(0x41);
13203     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13204
13205     key_state = GetKeyState(0x41);
13206     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13207
13208     DestroyWindow(test_window);
13209     flush_sequence();
13210 }
13211
13212 static const struct message WmHotkeyPressLWIN[] = {
13213     { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
13214     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
13215     { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
13216     { 0 }
13217 };
13218 static const struct message WmHotkeyPress[] = {
13219     { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
13220     { WM_HOTKEY, sent|wparam, 5 },
13221     { 0 }
13222 };
13223 static const struct message WmHotkeyRelease[] = {
13224     { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
13225     { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 0x80000001 },
13226     { WM_KEYUP, sent|lparam, 0, 0x80000001 },
13227     { 0 }
13228 };
13229 static const struct message WmHotkeyReleaseLWIN[] = {
13230     { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
13231     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
13232     { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
13233     { 0 }
13234 };
13235 static const struct message WmHotkeyCombined[] = {
13236     { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
13237     { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
13238     { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
13239     { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
13240     { WM_APP, sent, 0, 0 },
13241     { WM_HOTKEY, sent|wparam, 5 },
13242     { WM_APP+1, sent, 0, 0 },
13243     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
13244     { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
13245     { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
13246     { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
13247     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
13248     { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
13249     { 0 }
13250 };
13251 static const struct message WmHotkeyPrevious[] = {
13252     { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
13253     { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
13254     { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
13255     { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
13256     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
13257     { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
13258     { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 1 },
13259     { WM_KEYDOWN, sent|lparam, 0, 1 },
13260     { HCBT_KEYSKIPPED, hook|optional|lparam, 0, 0xc0000001 },
13261     { WM_KEYUP, sent|lparam, 0, 0xc0000001 },
13262     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
13263     { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
13264     { 0 }
13265 };
13266 static const struct message WmHotkeyNew[] = {
13267     { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
13268     { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
13269     { WM_HOTKEY, sent|wparam, 5 },
13270     { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
13271     { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
13272     { 0 }
13273 };
13274
13275 static int hotkey_letter;
13276
13277 static LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
13278 {
13279     struct recvd_message msg;
13280
13281     if (nCode == HC_ACTION)
13282     {
13283         KBDLLHOOKSTRUCT *kdbhookstruct = (KBDLLHOOKSTRUCT*)lParam;
13284
13285         msg.hwnd = 0;
13286         msg.message = wParam;
13287         msg.flags = kbd_hook|wparam|lparam;
13288         msg.wParam = kdbhookstruct->vkCode;
13289         msg.lParam = kdbhookstruct->flags;
13290         msg.descr = "KeyboardHookProc";
13291         add_message(&msg);
13292
13293         if (wParam == WM_KEYUP || wParam == WM_KEYDOWN)
13294         {
13295             ok(kdbhookstruct->vkCode == VK_LWIN || kdbhookstruct->vkCode == hotkey_letter,
13296                "unexpected keycode %x\n", kdbhookstruct->vkCode);
13297        }
13298     }
13299
13300     return CallNextHookEx(hKBD_hook, nCode, wParam, lParam);
13301 }
13302
13303 static void test_hotkey(void)
13304 {
13305     HWND test_window, taskbar_window;
13306     BOOL ret;
13307     MSG msg;
13308     DWORD queue_status;
13309     SHORT key_state;
13310
13311     SetLastError(0xdeadbeef);
13312     ret = UnregisterHotKey(NULL, 0);
13313     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13314     ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13315        "unexpected error %d\n", GetLastError());
13316
13317     if (ret == TRUE)
13318     {
13319         skip("hotkeys not supported\n");
13320         return;
13321     }
13322
13323     test_window = CreateWindowEx(0, "HotkeyWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13324                            100, 100, 200, 200, 0, 0, 0, NULL);
13325
13326     flush_sequence();
13327
13328     SetLastError(0xdeadbeef);
13329     ret = UnregisterHotKey(test_window, 0);
13330     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13331     ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13332        "unexpected error %d\n", GetLastError());
13333
13334     /* Search for a Windows Key + letter combination that hasn't been registered */
13335     for (hotkey_letter = 0x41; hotkey_letter <= 0x51; hotkey_letter ++)
13336     {
13337         SetLastError(0xdeadbeef);
13338         ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
13339
13340         if (ret == TRUE)
13341         {
13342             break;
13343         }
13344         else
13345         {
13346             ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13347                "unexpected error %d\n", GetLastError());
13348         }
13349     }
13350
13351     if (hotkey_letter == 0x52)
13352     {
13353         ok(0, "Couldn't find any free Windows Key + letter combination\n");
13354         goto end;
13355     }
13356
13357     hKBD_hook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProc, GetModuleHandle(NULL), 0);
13358     if (!hKBD_hook) win_skip("WH_KEYBOARD_LL is not supported\n");
13359
13360     /* Same key combination, different id */
13361     SetLastError(0xdeadbeef);
13362     ret = RegisterHotKey(test_window, 4, MOD_WIN, hotkey_letter);
13363     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13364     ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13365        "unexpected error %d\n", GetLastError());
13366
13367     /* Same key combination, different window */
13368     SetLastError(0xdeadbeef);
13369     ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
13370     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13371     ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13372        "unexpected error %d\n", GetLastError());
13373
13374     /* Register the same hotkey twice */
13375     SetLastError(0xdeadbeef);
13376     ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
13377     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13378     ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13379        "unexpected error %d\n", GetLastError());
13380
13381     /* Window on another thread */
13382     taskbar_window = FindWindowA("Shell_TrayWnd", NULL);
13383     if (!taskbar_window)
13384     {
13385         skip("no taskbar?\n");
13386     }
13387     else
13388     {
13389         SetLastError(0xdeadbeef);
13390         ret = RegisterHotKey(taskbar_window, 5, 0, hotkey_letter);
13391         ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13392         ok(GetLastError() == ERROR_WINDOW_OF_OTHER_THREAD || broken(GetLastError() == 0xdeadbeef),
13393            "unexpected error %d\n", GetLastError());
13394     }
13395
13396     /* Inject the appropriate key sequence */
13397     keybd_event(VK_LWIN, 0, 0, 0);
13398     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13399         DispatchMessage(&msg);
13400     ok_sequence(WmHotkeyPressLWIN, "window hotkey press LWIN", FALSE);
13401
13402     keybd_event(hotkey_letter, 0, 0, 0);
13403     queue_status = GetQueueStatus(QS_HOTKEY);
13404     ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
13405     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13406     {
13407         if (msg.message == WM_HOTKEY)
13408         {
13409             ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
13410             ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
13411         }
13412         DispatchMessage(&msg);
13413     }
13414     ok_sequence(WmHotkeyPress, "window hotkey press", FALSE);
13415
13416     queue_status = GetQueueStatus(QS_HOTKEY);
13417     ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
13418
13419     key_state = GetAsyncKeyState(hotkey_letter);
13420     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13421
13422     keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
13423     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13424         DispatchMessage(&msg);
13425     ok_sequence(WmHotkeyRelease, "window hotkey release", TRUE);
13426
13427     keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
13428     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13429         DispatchMessage(&msg);
13430     ok_sequence(WmHotkeyReleaseLWIN, "window hotkey release LWIN", FALSE);
13431
13432     /* normal posted WM_HOTKEY messages set QS_HOTKEY */
13433     PostMessage(test_window, WM_HOTKEY, 0, 0);
13434     queue_status = GetQueueStatus(QS_HOTKEY);
13435     ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
13436     queue_status = GetQueueStatus(QS_POSTMESSAGE);
13437     ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
13438     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13439         DispatchMessage(&msg);
13440     flush_sequence();
13441
13442     /* Send and process all messages at once */
13443     PostMessage(test_window, WM_APP, 0, 0);
13444     keybd_event(VK_LWIN, 0, 0, 0);
13445     keybd_event(hotkey_letter, 0, 0, 0);
13446     keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
13447     keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
13448
13449     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13450     {
13451         if (msg.message == WM_HOTKEY)
13452         {
13453             ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
13454             ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
13455         }
13456         DispatchMessage(&msg);
13457     }
13458     ok_sequence(WmHotkeyCombined, "window hotkey combined", FALSE);
13459
13460     /* Register same hwnd/id with different key combination */
13461     ret = RegisterHotKey(test_window, 5, 0, hotkey_letter);
13462     ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
13463
13464     /* Previous key combination does not work */
13465     keybd_event(VK_LWIN, 0, 0, 0);
13466     keybd_event(hotkey_letter, 0, 0, 0);
13467     keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
13468     keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
13469
13470     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13471         DispatchMessage(&msg);
13472     ok_sequence(WmHotkeyPrevious, "window hotkey previous", FALSE);
13473
13474     /* New key combination works */
13475     keybd_event(hotkey_letter, 0, 0, 0);
13476     keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
13477
13478     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13479     {
13480         if (msg.message == WM_HOTKEY)
13481         {
13482             ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
13483             ok(msg.lParam == MAKELPARAM(0, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
13484         }
13485         DispatchMessage(&msg);
13486     }
13487     ok_sequence(WmHotkeyNew, "window hotkey new", FALSE);
13488
13489     /* Unregister hotkey properly */
13490     ret = UnregisterHotKey(test_window, 5);
13491     ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
13492
13493     /* Unregister hotkey again */
13494     SetLastError(0xdeadbeef);
13495     ret = UnregisterHotKey(test_window, 5);
13496     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13497     ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13498        "unexpected error %d\n", GetLastError());
13499
13500     /* Register thread hotkey */
13501     ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
13502     ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
13503
13504     /* Inject the appropriate key sequence */
13505     keybd_event(VK_LWIN, 0, 0, 0);
13506     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13507     {
13508         ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
13509         DispatchMessage(&msg);
13510     }
13511     ok_sequence(WmHotkeyPressLWIN, "thread hotkey press LWIN", FALSE);
13512
13513     keybd_event(hotkey_letter, 0, 0, 0);
13514     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13515     {
13516         if (msg.message == WM_HOTKEY)
13517         {
13518             struct recvd_message message;
13519             ok(msg.hwnd == NULL, "unexpected hwnd %p\n", msg.hwnd);
13520             ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
13521             message.message = msg.message;
13522             message.flags = sent|wparam|lparam;
13523             message.wParam = msg.wParam;
13524             message.lParam = msg.lParam;
13525             message.descr = "test_hotkey thread message";
13526             add_message(&message);
13527         }
13528         else
13529             ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
13530         DispatchMessage(&msg);
13531     }
13532     ok_sequence(WmHotkeyPress, "thread hotkey press", FALSE);
13533
13534     keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
13535     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13536     {
13537         ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
13538         DispatchMessage(&msg);
13539     }
13540     ok_sequence(WmHotkeyRelease, "thread hotkey release", TRUE);
13541
13542     keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
13543     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13544     {
13545         ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
13546         DispatchMessage(&msg);
13547     }
13548     ok_sequence(WmHotkeyReleaseLWIN, "thread hotkey release LWIN", FALSE);
13549
13550     /* Unregister thread hotkey */
13551     ret = UnregisterHotKey(NULL, 5);
13552     ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
13553
13554     if (hKBD_hook) UnhookWindowsHookEx(hKBD_hook);
13555     hKBD_hook = NULL;
13556
13557 end:
13558     UnregisterHotKey(NULL, 5);
13559     UnregisterHotKey(test_window, 5);
13560     DestroyWindow(test_window);
13561     flush_sequence();
13562 }
13563
13564
13565 static const struct message WmSetFocus_1[] = {
13566     { HCBT_SETFOCUS, hook }, /* child */
13567     { HCBT_ACTIVATE, hook }, /* parent */
13568     { WM_QUERYNEWPALETTE, sent|wparam|lparam|parent|optional, 0, 0 },
13569     { WM_WINDOWPOSCHANGING, sent|parent, 0, SWP_NOSIZE|SWP_NOMOVE },
13570     { WM_ACTIVATEAPP, sent|wparam|parent, 1 },
13571     { WM_NCACTIVATE, sent|parent },
13572     { WM_GETTEXT, sent|defwinproc|parent|optional },
13573     { WM_GETTEXT, sent|defwinproc|parent|optional },
13574     { WM_ACTIVATE, sent|wparam|parent, 1 },
13575     { HCBT_SETFOCUS, hook }, /* parent */
13576     { WM_SETFOCUS, sent|defwinproc|parent },
13577     { WM_KILLFOCUS, sent|parent },
13578     { WM_SETFOCUS, sent },
13579     { 0 }
13580 };
13581 static const struct message WmSetFocus_2[] = {
13582     { HCBT_SETFOCUS, hook }, /* parent */
13583     { WM_KILLFOCUS, sent },
13584     { WM_SETFOCUS, sent|parent },
13585     { 0 }
13586 };
13587 static const struct message WmSetFocus_3[] = {
13588     { HCBT_SETFOCUS, hook }, /* child */
13589     { 0 }
13590 };
13591 static const struct message WmSetFocus_4[] = {
13592     { 0 }
13593 };
13594
13595 static void test_SetFocus(void)
13596 {
13597     HWND parent, old_parent, child, old_focus, old_active;
13598     MSG msg;
13599     struct wnd_event wnd_event;
13600     HANDLE hthread;
13601     DWORD ret, tid;
13602
13603     wnd_event.start_event = CreateEvent(NULL, 0, 0, NULL);
13604     ok(wnd_event.start_event != 0, "CreateEvent error %d\n", GetLastError());
13605     hthread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
13606     ok(hthread != 0, "CreateThread error %d\n", GetLastError());
13607     ret = WaitForSingleObject(wnd_event.start_event, INFINITE);
13608     ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
13609     CloseHandle(wnd_event.start_event);
13610
13611     parent = CreateWindowEx(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
13612                             0, 0, 0, 0, 0, 0, 0, NULL);
13613     ok(parent != 0, "failed to create parent window\n");
13614     child = CreateWindowEx(0, "TestWindowClass", NULL, WS_CHILD,
13615                            0, 0, 0, 0, parent, 0, 0, NULL);
13616     ok(child != 0, "failed to create child window\n");
13617
13618     trace("parent %p, child %p, thread window %p\n", parent, child, wnd_event.hwnd);
13619
13620     SetFocus(0);
13621     SetActiveWindow(0);
13622
13623     flush_events();
13624     flush_sequence();
13625
13626     ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
13627     ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
13628
13629     log_all_parent_messages++;
13630
13631     old_focus = SetFocus(child);
13632     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
13633     ok_sequence(WmSetFocus_1, "SetFocus on a child window", TRUE);
13634     ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
13635     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13636     ok(GetFocus() == child, "expected focus %p, got %p\n", child, GetFocus());
13637
13638     old_focus = SetFocus(parent);
13639     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
13640     ok_sequence(WmSetFocus_2, "SetFocus on a parent window", FALSE);
13641     ok(old_focus == child, "expected old focus %p, got %p\n", child, old_focus);
13642     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13643     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
13644
13645     SetLastError(0xdeadbeef);
13646     old_focus = SetFocus((HWND)0xdeadbeef);
13647     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
13648        "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
13649     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
13650     ok_sequence(WmEmptySeq, "SetFocus on an invalid window", FALSE);
13651     ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
13652     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13653     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
13654
13655     SetLastError(0xdeadbeef);
13656     old_focus = SetFocus(GetDesktopWindow());
13657     ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
13658        broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
13659     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
13660     ok_sequence(WmEmptySeq, "SetFocus on a desktop window", TRUE);
13661     ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
13662     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13663     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
13664
13665     SetLastError(0xdeadbeef);
13666     old_focus = SetFocus(wnd_event.hwnd);
13667     ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
13668        broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
13669     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
13670     ok_sequence(WmEmptySeq, "SetFocus on another thread window", TRUE);
13671     ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
13672     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13673     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
13674
13675     SetLastError(0xdeadbeef);
13676     old_active = SetActiveWindow((HWND)0xdeadbeef);
13677     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
13678        "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
13679     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
13680     ok_sequence(WmEmptySeq, "SetActiveWindow on an invalid window", FALSE);
13681     ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
13682     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13683     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
13684
13685     SetLastError(0xdeadbeef);
13686     old_active = SetActiveWindow(GetDesktopWindow());
13687 todo_wine
13688     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
13689     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
13690     ok_sequence(WmEmptySeq, "SetActiveWindow on a desktop window", TRUE);
13691     ok(old_active == 0, "expected old focus 0, got %p\n", old_focus);
13692     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13693     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
13694
13695     SetLastError(0xdeadbeef);
13696     old_active = SetActiveWindow(wnd_event.hwnd);
13697 todo_wine
13698     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
13699     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
13700     ok_sequence(WmEmptySeq, "SetActiveWindow on another thread window", TRUE);
13701     ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
13702     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13703     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
13704
13705     SetLastError(0xdeadbeef);
13706     ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE);
13707     ok(ret, "AttachThreadInput error %d\n", GetLastError());
13708
13709 todo_wine {
13710     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13711     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
13712 }
13713     flush_events();
13714     flush_sequence();
13715
13716     old_focus = SetFocus(wnd_event.hwnd);
13717     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
13718     ok(old_focus == wnd_event.hwnd, "expected old focus %p, got %p\n", wnd_event.hwnd, old_focus);
13719     ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
13720     ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
13721
13722     old_focus = SetFocus(parent);
13723     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
13724     ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
13725     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13726     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
13727
13728     flush_events();
13729     flush_sequence();
13730
13731     old_active = SetActiveWindow(wnd_event.hwnd);
13732     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
13733     ok(old_active == parent, "expected old focus %p, got %p\n", parent, old_active);
13734     ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
13735     ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
13736
13737     SetLastError(0xdeadbeef);
13738     ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE);
13739     ok(ret, "AttachThreadInput error %d\n", GetLastError());
13740
13741     ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
13742     ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
13743
13744     old_parent = SetParent(child, GetDesktopWindow());
13745     ok(old_parent == parent, "expected old parent %p, got %p\n", parent, old_parent);
13746
13747     ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
13748     ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
13749
13750     old_focus = SetFocus(parent);
13751     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
13752     ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
13753     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13754     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
13755
13756     flush_events();
13757     flush_sequence();
13758
13759     SetLastError(0xdeadbeef);
13760     old_focus = SetFocus(child);
13761 todo_wine
13762     ok(GetLastError() == ERROR_INVALID_PARAMETER /* Vista+ */ ||
13763        broken(GetLastError() == 0) /* XP */ ||
13764        broken(GetLastError() == 0xdeadbeef), "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
13765     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
13766     ok_sequence(WmSetFocus_3, "SetFocus on a child window", TRUE);
13767     ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
13768     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13769     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
13770
13771     SetLastError(0xdeadbeef);
13772     old_active = SetActiveWindow(child);
13773     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
13774     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
13775     ok_sequence(WmEmptySeq, "SetActiveWindow on a child window", FALSE);
13776     ok(old_active == parent, "expected old active %p, got %p\n", parent, old_active);
13777     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13778     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
13779
13780     log_all_parent_messages--;
13781
13782     DestroyWindow(child);
13783     DestroyWindow(parent);
13784
13785     ret = PostMessage(wnd_event.hwnd, WM_QUIT, 0, 0);
13786     ok(ret, "PostMessage(WM_QUIT) error %d\n", GetLastError());
13787     ret = WaitForSingleObject(hthread, INFINITE);
13788     ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
13789     CloseHandle(hthread);
13790 }
13791
13792 static const struct message WmSetLayeredStyle[] = {
13793     { WM_STYLECHANGING, sent },
13794     { WM_STYLECHANGED, sent },
13795     { WM_GETTEXT, sent|defwinproc|optional },
13796     { 0 }
13797 };
13798
13799 static const struct message WmSetLayeredStyle2[] = {
13800     { WM_STYLECHANGING, sent },
13801     { WM_STYLECHANGED, sent },
13802     { WM_WINDOWPOSCHANGING, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13803     { WM_NCCALCSIZE, sent|optional|wparam|defwinproc, 1 },
13804     { WM_WINDOWPOSCHANGED, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13805     { WM_MOVE, sent|optional|defwinproc|wparam, 0 },
13806     { WM_SIZE, sent|optional|defwinproc|wparam, SIZE_RESTORED },
13807     { 0 }
13808 };
13809
13810 struct layered_window_info
13811 {
13812     HWND   hwnd;
13813     HDC    hdc;
13814     SIZE   size;
13815     HANDLE event;
13816     BOOL   ret;
13817 };
13818
13819 static DWORD CALLBACK update_layered_proc( void *param )
13820 {
13821     struct layered_window_info *info = param;
13822     POINT src = { 0, 0 };
13823
13824     info->ret = pUpdateLayeredWindow( info->hwnd, 0, NULL, &info->size,
13825                                       info->hdc, &src, 0, NULL, ULW_OPAQUE );
13826     ok( info->ret, "failed\n");
13827     SetEvent( info->event );
13828     return 0;
13829 }
13830
13831 static void test_layered_window(void)
13832 {
13833     HWND hwnd;
13834     HDC hdc;
13835     HBITMAP bmp;
13836     BOOL ret;
13837     SIZE size;
13838     POINT pos, src;
13839     RECT rect, client;
13840     HANDLE thread;
13841     DWORD tid;
13842     struct layered_window_info info;
13843
13844     if (!pUpdateLayeredWindow)
13845     {
13846         win_skip( "UpdateLayeredWindow not supported\n" );
13847         return;
13848     }
13849
13850     hdc = CreateCompatibleDC( 0 );
13851     bmp = CreateCompatibleBitmap( hdc, 300, 300 );
13852     SelectObject( hdc, bmp );
13853
13854     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_CAPTION | WS_THICKFRAME | WS_SYSMENU,
13855                            100, 100, 300, 300, 0, 0, 0, NULL);
13856     ok( hwnd != 0, "failed to create window\n" );
13857     ShowWindow( hwnd, SW_SHOWNORMAL );
13858     UpdateWindow( hwnd );
13859     flush_events();
13860     flush_sequence();
13861
13862     GetWindowRect( hwnd, &rect );
13863     GetClientRect( hwnd, &client );
13864     ok( client.right < rect.right - rect.left, "wrong client area\n" );
13865     ok( client.bottom < rect.bottom - rect.top, "wrong client area\n" );
13866
13867     src.x = src.y = 0;
13868     pos.x = pos.y = 300;
13869     size.cx = size.cy = 250;
13870     ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
13871     ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
13872     ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
13873     SetWindowLong( hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
13874     ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
13875
13876     ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
13877     ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
13878     ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
13879     GetWindowRect( hwnd, &rect );
13880     ok( rect.left == 300 && rect.top == 300 && rect.right == 550 && rect.bottom == 550,
13881         "wrong window rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
13882     GetClientRect( hwnd, &rect );
13883     ok( rect.right == client.right - 50 && rect.bottom == client.bottom - 50,
13884         "wrong client rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
13885
13886     size.cx = 150;
13887     pos.y = 200;
13888     ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
13889     ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
13890     ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
13891     GetWindowRect( hwnd, &rect );
13892     ok( rect.left == 300 && rect.top == 200 && rect.right == 450 && rect.bottom == 450,
13893         "wrong window rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
13894     GetClientRect( hwnd, &rect );
13895     ok( rect.right == client.right - 150 && rect.bottom == client.bottom - 50,
13896         "wrong client rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
13897
13898     SetWindowLong( hwnd, GWL_STYLE,
13899                    GetWindowLong(hwnd, GWL_STYLE) & ~(WS_CAPTION | WS_THICKFRAME | WS_SYSMENU) );
13900     ok_sequence( WmSetLayeredStyle2, "WmSetLayeredStyle2", FALSE );
13901
13902     size.cx = 200;
13903     pos.x = 200;
13904     ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
13905     ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
13906     ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
13907     GetWindowRect( hwnd, &rect );
13908     ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
13909         "wrong window rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
13910     GetClientRect( hwnd, &rect );
13911     ok( (rect.right == 200 && rect.bottom == 250) ||
13912         broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
13913         "wrong client rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
13914
13915     size.cx = 0;
13916     ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
13917     ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
13918     ok( GetLastError() == ERROR_INVALID_PARAMETER || broken(ERROR_MR_MID_NOT_FOUND) /* win7 */,
13919         "wrong error %u\n", GetLastError() );
13920     size.cx = 1;
13921     size.cy = -1;
13922     ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
13923     ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
13924     ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
13925
13926     SetWindowLong( hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED );
13927     ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
13928     GetWindowRect( hwnd, &rect );
13929     ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
13930         "wrong window rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
13931     GetClientRect( hwnd, &rect );
13932     ok( (rect.right == 200 && rect.bottom == 250) ||
13933         broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
13934         "wrong client rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
13935
13936     SetWindowLong( hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
13937     info.hwnd = hwnd;
13938     info.hdc = hdc;
13939     info.size.cx = 250;
13940     info.size.cy = 300;
13941     info.event = CreateEventA( NULL, TRUE, FALSE, NULL );
13942     info.ret = FALSE;
13943     thread = CreateThread( NULL, 0, update_layered_proc, &info, 0, &tid );
13944     ok( WaitForSingleObject( info.event, 1000 ) == 0, "wait failed\n" );
13945     ok( info.ret, "UpdateLayeredWindow failed in other thread\n" );
13946     WaitForSingleObject( thread, 1000 );
13947     CloseHandle( thread );
13948     GetWindowRect( hwnd, &rect );
13949     ok( rect.left == 200 && rect.top == 200 && rect.right == 450 && rect.bottom == 500,
13950         "wrong window rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
13951     GetClientRect( hwnd, &rect );
13952     ok( (rect.right == 250 && rect.bottom == 300) ||
13953         broken(rect.right == client.right - 50 && rect.bottom == client.bottom),
13954         "wrong client rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
13955
13956     DestroyWindow( hwnd );
13957     DeleteDC( hdc );
13958     DeleteObject( bmp );
13959 }
13960
13961 START_TEST(msg)
13962 {
13963     char **test_argv;
13964     BOOL ret;
13965     BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
13966     HMODULE hModuleImm32;
13967     BOOL (WINAPI *pImmDisableIME)(DWORD);
13968
13969     int argc = winetest_get_mainargs( &test_argv );
13970     if (argc >= 3)
13971     {
13972         unsigned int arg;
13973         /* Child process. */
13974         sscanf (test_argv[2], "%d", (unsigned int *) &arg);
13975         do_wait_idle_child( arg );
13976         return;
13977     }
13978
13979     init_procs();
13980
13981     hModuleImm32 = LoadLibrary("imm32.dll");
13982     if (hModuleImm32) {
13983         pImmDisableIME = (void *)GetProcAddress(hModuleImm32, "ImmDisableIME");
13984         if (pImmDisableIME)
13985             pImmDisableIME(0);
13986     }
13987     pImmDisableIME = NULL;
13988     FreeLibrary(hModuleImm32);
13989
13990     if (!RegisterWindowClasses()) assert(0);
13991
13992     if (pSetWinEventHook)
13993     {
13994         hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
13995                                        GetModuleHandleA(0), win_event_proc,
13996                                        0, GetCurrentThreadId(),
13997                                        WINEVENT_INCONTEXT);
13998         if (pIsWinEventHookInstalled && hEvent_hook)
13999         {
14000             UINT event;
14001             for (event = EVENT_MIN; event <= EVENT_MAX; event++)
14002                 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
14003         }
14004     }
14005     if (!hEvent_hook) win_skip( "no win event hook support\n" );
14006
14007     cbt_hook_thread_id = GetCurrentThreadId();
14008     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
14009     if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
14010
14011     test_winevents();
14012
14013     /* Fix message sequences before removing 4 lines below */
14014 #if 1
14015     if (pUnhookWinEvent && hEvent_hook)
14016     {
14017         ret = pUnhookWinEvent(hEvent_hook);
14018         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
14019         pUnhookWinEvent = 0;
14020     }
14021     hEvent_hook = 0;
14022 #endif
14023
14024     test_SetFocus();
14025     test_SetParent();
14026     test_PostMessage();
14027     test_ShowWindow();
14028     test_PeekMessage();
14029     test_PeekMessage2();
14030     test_WaitForInputIdle( test_argv[0] );
14031     test_scrollwindowex();
14032     test_messages();
14033     test_setwindowpos();
14034     test_showwindow();
14035     invisible_parent_tests();
14036     test_mdi_messages();
14037     test_button_messages();
14038     test_static_messages();
14039     test_listbox_messages();
14040     test_combobox_messages();
14041     test_wmime_keydown_message();
14042     test_paint_messages();
14043     test_interthread_messages();
14044     test_message_conversion();
14045     test_accelerators();
14046     test_timers();
14047     test_timers_no_wnd();
14048     if (hCBT_hook) test_set_hook();
14049     test_DestroyWindow();
14050     test_DispatchMessage();
14051     test_SendMessageTimeout();
14052     test_edit_messages();
14053     test_quit_message();
14054     test_SetActiveWindow();
14055
14056     if (!pTrackMouseEvent)
14057         win_skip("TrackMouseEvent is not available\n");
14058     else
14059         test_TrackMouseEvent();
14060
14061     test_SetWindowRgn();
14062     test_sys_menu();
14063     test_dialog_messages();
14064     test_EndDialog();
14065     test_nullCallback();
14066     test_dbcs_wm_char();
14067     test_menu_messages();
14068     test_paintingloop();
14069     test_defwinproc();
14070     test_clipboard_viewers();
14071     test_keyflags();
14072     test_hotkey();
14073     test_layered_window();
14074     /* keep it the last test, under Windows it tends to break the tests
14075      * which rely on active/foreground windows being correct.
14076      */
14077     test_SetForegroundWindow();
14078
14079     UnhookWindowsHookEx(hCBT_hook);
14080     if (pUnhookWinEvent && hEvent_hook)
14081     {
14082         ret = pUnhookWinEvent(hEvent_hook);
14083         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
14084         SetLastError(0xdeadbeef);
14085         ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
14086         ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
14087            GetLastError() == 0xdeadbeef, /* Win9x */
14088            "unexpected error %d\n", GetLastError());
14089     }
14090 }